From 00952806f25a4c8fa8a50c7bcb05828d8c67ebed Mon Sep 17 00:00:00 2001
From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com>
Date: Thu, 13 Aug 2026 04:58:07 +0000
Subject: [PATCH 1/6] fix(www): correct three outdated pricing page FAQ answers
(#49036)
---
apps/www/data/PricingFAQ.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/apps/www/data/PricingFAQ.json b/apps/www/data/PricingFAQ.json
index 222e0620e9ef6..4a268d4c1804a 100644
--- a/apps/www/data/PricingFAQ.json
+++ b/apps/www/data/PricingFAQ.json
@@ -17,19 +17,19 @@
},
{
"question": "Are you going to change your pricing in the future?",
- "answer": "Our pricing is in Beta. You can read more about our decisions in our [pricing blog post](/blog/2021/03/29/pricing). Pricing may change in the future, however as a team of developers we are committed to pricing being as developer friendly as possible."
+ "answer": "Pricing may change in the future. As a team of developers, we are committed to keeping our pricing as developer friendly as possible."
},
{
"question": "What happens if I cancel my subscription?",
"answer": "The organization is allocated credits for unused time during the billing month. Those credits can be used for other projects."
},
{
- "question": "Do I get a notification if I am approaching my usage limits?",
- "answer": "Yes, we will email you when you are within 20% of your Plan limits."
+ "question": "How can I track my usage?",
+ "answer": "You can track your organization's usage at any time on the [usage page](https://supabase.com/dashboard/org/_/usage) in the dashboard, which shows how each project is tracking against your plan's limits. Your upcoming invoice on the [billing page](https://supabase.com/dashboard/org/_/billing) updates as you go, and organizations on the Pro Plan or above can use the [Spend cap](https://supabase.com/docs/guides/platform/cost-control) to control costs."
},
{
"question": "What if I need one project for development and one for production?",
- "answer": "We are working on multi-environment projects. For now, you can create a project for your development backend and production backend. We give you 2 free projects as part of our Free Plan. This means you could have a development and a production server as part of your Free Plan."
+ "answer": "You can create two projects, one for development and one for production — the Free Plan includes two free projects. You can also use [Branching](https://supabase.com/docs/guides/deployment/branching), available on the Pro Plan and above, to run a separate development environment off your production project."
},
{
"question": "Can I self-host Supabase for free?",
From 2f8181b8bb3714775bca6fcf94a4fff9e66cdadb Mon Sep 17 00:00:00 2001
From: Saxon Fletcher
Date: Thu, 13 Aug 2026 16:00:39 +1000
Subject: [PATCH 2/6] refactor: decouple assistant chat surfaces (#48973)
## Summary
- extract the reusable assistant conversation body from the sidebar
interface
- drive shared chat rendering and mutations with an explicit chat ID
- keep sidebar selection, shortcuts, SQL-editor context, and header
controls in the sidebar wrapper
- add selection-free chat creation and branching primitives while
preserving existing sidebar helpers
- add store tests for cross-surface selection and mutation isolation
This is PR 1 of 3. Review this foundation first, then #49031 for the
routed Explorer chat lifecycle, followed by #49032 for discovery and
cross-surface entry points.
Supersedes #48970 after renaming the branch to use the repository's
`chore/` convention.
## Test plan
- `mise exec node@22 -- pnpm --dir apps/studio exec tsc --noEmit`
- `mise exec node@22 -- pnpm --dir apps/studio exec vitest run
state/ai-assistant-state.test.ts`
- ESLint on changed files
- Prettier on changed files
---
.../ui/AIAssistantPanel/AIAssistant.tsx | 718 ++----------------
.../AIAssistantChatSelector.tsx | 14 +-
.../ui/AIAssistantPanel/AIAssistantHeader.tsx | 10 +-
.../ui/AIAssistantPanel/AssistantChat.tsx | 707 +++++++++++++++++
.../ui/AIAssistantPanel/Message.Context.tsx | 1 +
.../ui/AIAssistantPanel/Message.tsx | 8 +-
apps/studio/state/ai-assistant-state.test.ts | 81 +-
apps/studio/state/ai-assistant-state.tsx | 148 ++--
8 files changed, 955 insertions(+), 732 deletions(-)
create mode 100644 apps/studio/components/ui/AIAssistantPanel/AssistantChat.tsx
diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx
index 02c2844a13950..8b2b0b1776f81 100644
--- a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx
@@ -1,59 +1,14 @@
import type { UIMessage as MessageType } from '@ai-sdk/react'
-import { useChat } from '@ai-sdk/react'
-import { lastAssistantMessageIsCompleteWithApprovalResponses } from 'ai'
-import { LOCAL_STORAGE_KEYS, useFlag } from 'common'
-import { useParams, useSearchParamsShallow } from 'common/hooks'
-import { AnimatePresence, motion } from 'framer-motion'
-import { Eraser, Pencil, X } from 'lucide-react'
+import { useParams } from 'common/hooks'
import { useRouter } from 'next/router'
-import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import { Button, cn, KeyboardShortcut } from 'ui'
-import { Admonition } from 'ui-patterns/Admonition'
+import { useEffect } from 'react'
-import { AlertError } from '../AlertError'
-import { ButtonTooltip } from '../ButtonTooltip'
-import { ErrorBoundary } from '../ErrorBoundary/ErrorBoundary'
-import { InlineLinkClassName } from '../InlineLink'
-import { ASSISTANT_ERRORS } from './AiAssistant.constants'
-import {
- containsLogsSnippets,
- hasPendingToolApproval,
- onErrorChat,
- resolvePendingToolApprovalsAsDenied,
-} from './AIAssistant.utils'
import { AIAssistantHeader } from './AIAssistantHeader'
-import { AIOnboarding } from './AIOnboarding'
-import { AssistantChatForm } from './AssistantChatForm'
-import {
- Conversation,
- ConversationContent,
- ConversationScrollButton,
-} from './elements/Conversation'
-import { Message } from './Message'
-import { Markdown } from '@/components/interfaces/Markdown'
+import { AssistantChat } from './AssistantChat'
import { resolveSnippetSource } from '@/components/interfaces/SQLEditor/querySource'
import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
-import { useCheckOpenAIKeyQuery } from '@/data/ai/check-api-key-query'
-import { useRateMessageMutation } from '@/data/ai/rate-message-mutation'
-import { useTablesQuery } from '@/data/tables/tables-query'
-import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
-import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
-import { useOrgAiOptInLevel } from '@/hooks/misc/useOrgOptedIntoAi'
-import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
-import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
-import type { AssistantMessageMetadata } from '@/lib/ai/assistant-message-metadata'
-import { getParallelApprovalIdsToReject } from '@/lib/ai/message-utils'
-import {
- DEFAULT_ASSISTANT_BASE_MODEL_ID,
- defaultAssistantModelId,
- isAssistantBaseModelId,
- isKnownAssistantModelId,
-} from '@/lib/ai/model.utils'
-import { IS_PLATFORM } from '@/lib/constants'
-import { uuidv4 } from '@/lib/helpers'
-import { useTrack } from '@/lib/telemetry/track'
-import type { AssistantModel, SqlSnippet } from '@/state/ai-assistant-state'
import { useAiAssistantState, useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
+import type { SqlSnippet } from '@/state/ai-assistant-state'
import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
import { useShortcut } from '@/state/shortcuts/useShortcut'
import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
@@ -64,646 +19,89 @@ interface AIAssistantProps {
className?: string
}
+type CurrentQuerySnippet = Exclude
+
+const isSameSnippet = (snippet: SqlSnippet, currentQuery: CurrentQuerySnippet) =>
+ typeof snippet !== 'string' &&
+ snippet.label === currentQuery.label &&
+ snippet.content === currentQuery.content &&
+ snippet.source === currentQuery.source
+
export const AIAssistant = ({ className }: AIAssistantProps) => {
const router = useRouter()
const { id: entityId, source: sourceParam } = useParams()
- const { data: project } = useSelectedProjectQuery()
- const searchParams = useSearchParamsShallow()
-
- const { data: selectedOrganization, isPending: isLoadingOrganization } =
- useSelectedOrganizationQuery()
-
- useShortcut(SHORTCUT_IDS.AI_ASSISTANT_CANCEL_EDIT, () => cancelEdit())
- useShortcut(SHORTCUT_IDS.AI_ASSISTANT_NEW_CHAT, () => snap.newChat())
-
- const disablePrompts = useFlag('disableAssistantPrompts')
- const { snippets } = useSqlEditorV2StateSnapshot()
const snap = useAiAssistantStateSnapshot()
const state = useAiAssistantState()
+ const { snippets } = useSqlEditorV2StateSnapshot()
const { activeSidebar, closeSidebar } = useSidebarManagerSnapshot()
+ const shortcutsEnabled = activeSidebar?.id === SIDEBAR_KEYS.AI_ASSISTANT
- const { hasAccess: hasAccessToAdvanceModel, isLoading: isLoadingEntitlements } =
- useCheckEntitlements('assistant.advance_model')
-
- const selectedModel = useMemo(() => {
- // While entitlements are loading, use the stored model without enforcing access
- if (isLoadingEntitlements) {
- return snap.model ?? DEFAULT_ASSISTANT_BASE_MODEL_ID
- }
-
- const defaultModel = defaultAssistantModelId(hasAccessToAdvanceModel)
- const model = snap.model ?? defaultModel
-
- if (!isKnownAssistantModelId(model)) return defaultModel
- if (!hasAccessToAdvanceModel && !isAssistantBaseModelId(model)) {
- return DEFAULT_ASSISTANT_BASE_MODEL_ID
- }
-
- return model
- }, [isLoadingEntitlements, hasAccessToAdvanceModel, snap.model])
-
- const [updatedOptInSinceMCP] = useLocalStorageQuery(
- LOCAL_STORAGE_KEYS.AI_ASSISTANT_MCP_OPT_IN,
- false
- )
-
- const inputRef = useRef(null)
-
- const { aiOptInLevel, isHipaaProjectDisallowed } = useOrgAiOptInLevel()
- // Whether attached queries are sent at all. One definition, shared by the chat form
- // (which folds them into the message text) and the message metadata (which states
- // whether any of them was a logs query), so the two can't disagree.
- const includeSnippetsInMessage = aiOptInLevel !== 'disabled'
- const showMetadataWarning =
- IS_PLATFORM &&
- !!selectedOrganization &&
- (aiOptInLevel === 'disabled' || aiOptInLevel === 'schema')
-
- // Add a ref to store the last user message
- const lastUserMessageRef = useRef(null)
-
- // Keep latest selected organization to avoid stale values in useChat transport
- const selectedOrganizationRef = useRef(selectedOrganization)
- useEffect(() => {
- selectedOrganizationRef.current = selectedOrganization
- }, [selectedOrganization])
-
- const [value, setValue] = useState(snap.initialInput || '')
- const [editingMessageId, setEditingMessageId] = useState(null)
- const [isResubmitting, setIsResubmitting] = useState(false)
- const [messageRatings, setMessageRatings] = useState>({})
+ const handleNewChat = () => state.newChat()
- const { data: check, isSuccess } = useCheckOpenAIKeyQuery()
- const isApiKeySet = !!check?.hasKey
-
- const { mutateAsync: rateMessage } = useRateMessageMutation()
+ useShortcut(SHORTCUT_IDS.AI_ASSISTANT_NEW_CHAT, handleNewChat, {
+ enabled: shortcutsEnabled,
+ })
const isInSQLEditor = router.pathname.includes('/sql/[id]')
const snippet = snippets[entityId ?? '']
const snippetContent = snippet?.snippet?.content?.unchecked_sql
-
const openSnippetSource = isInSQLEditor
? resolveSnippetSource(snippet?.snippet, sourceParam)
: undefined
- const { data: tables } = useTablesQuery(
- {
- projectRef: project?.ref,
- connectionString: project?.connectionString,
- schema: 'public',
- },
- { enabled: isApiKeySet }
- )
-
- const currentTable = tables?.find((t) => t.id.toString() === entityId)
- const currentSchema = searchParams?.get('schema') ?? 'public'
-
- // Update context in state
useEffect(() => {
- state.setContext({
- projectRef: project?.ref,
- orgSlug: selectedOrganizationRef.current?.slug,
- connectionString: project?.connectionString ?? '',
- })
- }, [project?.ref, project?.connectionString, selectedOrganizationRef.current?.slug, state])
-
- const track = useTrack()
-
- const {
- messages: chatMessages,
- status: chatStatus,
- error,
- sendMessage,
- setMessages,
- addToolApprovalResponse,
- stop,
- regenerate,
- } = useChat({
- id: snap.activeChatId,
- ...(snap.activeChatId && snap.chatInstances[snap.activeChatId]
- ? { chat: snap.chatInstances[snap.activeChatId] }
- : {}),
- sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
- onError: onErrorChat,
- })
-
- const isChatLoading = chatStatus === 'submitted' || chatStatus === 'streaming'
- const hasPendingApproval = hasPendingToolApproval(chatMessages)
- const supportMetadata = snap.activeChat?.supportMetadata
- const isSupportChat = !!supportMetadata?.isSupportChat
- const isSupportChatClosed = isSupportChat && supportMetadata.lifecycleStatus !== 'bot_active'
- const activeChatId = snap.activeChatId
- const supportConversationId = supportMetadata?.frontConversationId
- const isChatInputDisabled =
- !isApiKeySet || disablePrompts || isLoadingOrganization || isSupportChatClosed
-
- const branchedFrom = snap.activeChat?.branchedFrom
- const branchedConversation = branchedFrom ? snap.chats[branchedFrom.chatId] : undefined
-
- const deleteMessageFromHere = useCallback(
- (messageId: string) => {
- // Find the message index in current chatMessages
- const messageIndex = chatMessages.findIndex((msg) => msg.id === messageId)
- if (messageIndex === -1) return
-
- if (isChatLoading) stop()
-
- snap.deleteMessagesAfter(messageId, { includeSelf: true })
-
- const updatedMessages = chatMessages.slice(0, messageIndex)
- setMessages(updatedMessages)
- },
- [snap, setMessages, chatMessages, isChatLoading, stop]
- )
-
- const editMessage = useCallback(
- (messageId: string) => {
- const messageIndex = chatMessages.findIndex((msg) => msg.id === messageId)
- if (messageIndex === -1) return
-
- // Target message
- const messageToEdit = chatMessages[messageIndex]
-
- // Activate editing mode
- setEditingMessageId(messageId)
- const textContent =
- messageToEdit.parts
- ?.filter((part) => part.type === 'text')
- .map((part) => part.text)
- .join('') ?? ''
- setValue(textContent)
-
- setTimeout(() => {
- if (inputRef.current) {
- inputRef?.current?.focus()
+ if (!shortcutsEnabled || !isInSQLEditor || !snippetContent) return
- // [Joshen] This is just to make the cursor go to the end of the text when focusing
- const val = inputRef.current.value
- inputRef.current.value = ''
- inputRef.current.value = val
- }
- }, 100)
- },
- [chatMessages, setValue]
- )
-
- const cancelEdit = useCallback(() => {
- setEditingMessageId(null)
- setValue('')
- }, [setValue])
-
- const handleRateMessage = useCallback(
- async (messageId: string, rating: 'positive' | 'negative', reason?: string) => {
- if (!project?.ref || !selectedOrganization?.slug) return
-
- // Optimistically update UI
- setMessageRatings((prev) => ({ ...prev, [messageId]: rating }))
-
- try {
- const result = await rateMessage({
- rating,
- messages: chatMessages,
- messageId,
- projectRef: project.ref,
- orgSlug: selectedOrganization.slug,
- reason,
- spanId: state.messageSpanIds[messageId],
- })
-
- track('assistant_message_rating_submitted', {
- rating,
- category: result.category,
- ...(reason && { reason }),
- chatId: state.activeChatId,
- })
- } catch (error) {
- console.error('Failed to rate message:', error)
- // Rollback on error
- setMessageRatings((prev) => {
- const { [messageId]: _, ...rest } = prev
- return rest
- })
- }
- },
- [chatMessages, project?.ref, selectedOrganization?.slug, rateMessage, track, state]
- )
-
- const isContextExceededError =
- error &&
- (error.message?.includes('context_length_exceeded') ||
- error.message?.includes('exceeds the context window'))
-
- const renderedMessages = useMemo(
- () =>
- chatMessages.map((message, index) => {
- const isBeingEdited = editingMessageId === message.id
- const isAfterEditedMessage = editingMessageId
- ? chatMessages.findIndex((m) => m.id === editingMessageId) < index
- : false
- const isLastMessage = index === chatMessages.length - 1
-
- return (
-
-
- {branchedConversation && branchedFrom?.messageId === message.id && (
-
-
-
- Branched from
-
-
-
-
- )}
-
- )
- }),
- [
- chatMessages,
- deleteMessageFromHere,
- editMessage,
- cancelEdit,
- editingMessageId,
- chatStatus,
- addToolApprovalResponse,
- handleRateMessage,
- messageRatings,
- branchedConversation,
- branchedFrom,
- snap,
- ]
- )
-
- const hasMessages = chatMessages.length > 0
-
- const sendMessageToAssistant = (finalContent: string) => {
- if (editingMessageId) {
- // Handling when the user is in edit mode
- // delete the message(s) from the chat just like the delete button
- setIsResubmitting(true)
- deleteMessageFromHere(editingMessageId)
- setEditingMessageId(null)
- }
-
- // Read off the attachments this message actually carries, so detaching the
- // "Current Query" chip also drops the claim. Gated on the same condition that
- // decides whether attachments make it into the text at all: with AI opt-in
- // disabled the chip is shown but no query is sent, and claiming otherwise would
- // have the server prepend ClickHouse context for a message holding no query.
- // Rides on the message rather than the request, so a Retry reproduces the context
- // the message was asked in.
- const metadata: AssistantMessageMetadata = {
- containsLogsSnippets: includeSnippetsInMessage && containsLogsSnippets(snap.sqlSnippets),
- }
-
- const payload = {
- role: 'user',
- createdAt: new Date(),
- parts: [{ type: 'text', text: finalContent }],
- id: uuidv4(),
- metadata,
- } as MessageType
-
- snap.clearSqlSnippets()
- lastUserMessageRef.current = payload
- if (hasPendingApproval && !editingMessageId) {
- setMessages(resolvePendingToolApprovalsAsDenied(chatMessages))
- }
- sendMessage(payload, {
- body: {
- schema: currentSchema,
- table: currentTable?.name,
- },
- })
- setValue('')
-
- if (finalContent.includes('Help me to debug')) {
- track('assistant_debug_submitted', { chatId: snap.activeChatId })
- } else {
- track('assistant_prompt_submitted', { chatId: snap.activeChatId })
- }
- }
-
- const handleClearMessages = () => {
- if (isChatLoading) stop()
- snap.clearMessages()
- setMessages([])
- lastUserMessageRef.current = null
- setEditingMessageId(null)
- }
-
- useEffect(() => {
- // Keep "Thinking" visible while stopping and resubmitting during edit
- // Only clear once the new response actually starts streaming (or errors)
- if (isResubmitting && (chatStatus === 'streaming' || !!error)) {
- setIsResubmitting(false)
+ const currentQuery = {
+ label: 'Current Query',
+ content: snippetContent,
+ source: openSnippetSource,
}
- }, [isResubmitting, chatStatus, error])
+ state.setSqlSnippets([currentQuery])
- useEffect(() => {
- // Approval-required tools can't run in parallel. Auto-deny extras so the model reissues them sequentially.
- for (const id of getParallelApprovalIdsToReject(chatMessages)) {
- addToolApprovalResponse?.({
- id,
- approved: false,
- reason:
- 'Only one approval-required tool call is allowed per turn. Please reissue this tool call after the current one completes.',
- })
- }
- }, [chatMessages, addToolApprovalResponse])
+ return () => {
+ const currentSnippets = state.sqlSnippets
+ const remainingSnippets = currentSnippets?.filter(
+ (snippet) => !isSameSnippet(snippet, currentQuery)
+ )
- useEffect(() => {
- setValue(snap.initialInput || '')
- if (inputRef.current && snap.initialInput) {
- inputRef.current.focus()
- inputRef.current.setSelectionRange(snap.initialInput.length, snap.initialInput.length)
+ if (currentSnippets && remainingSnippets?.length !== currentSnippets.length) {
+ state.setSqlSnippets(remainingSnippets ?? [])
+ }
}
- }, [snap.initialInput])
+ }, [shortcutsEnabled, isInSQLEditor, snippetContent, openSnippetSource, state])
- useEffect(() => {
- const isOpen = activeSidebar?.id === SIDEBAR_KEYS.AI_ASSISTANT
- if (isOpen && isInSQLEditor && !!snippetContent) {
- snap.setSqlSnippets([
- { label: 'Current Query', content: snippetContent, source: openSnippetSource },
- ])
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [activeSidebar?.id, isInSQLEditor, snippetContent, openSnippetSource])
+ if (!snap.activeChatId) return null
return (
- state.selectChat(chatId)}
+ onBranchChat={(messageId) => state.branchChat(messageId)}
+ composerContext={{
+ initialInput: snap.initialInput,
+ sqlSnippets: snap.sqlSnippets as SqlSnippet[] | undefined,
+ suggestions: snap.suggestions
+ ? {
+ title: snap.suggestions.title,
+ prompts: snap.suggestions.prompts?.map((prompt) => ({ ...prompt })),
+ }
+ : undefined,
+ onSetSqlSnippets: state.setSqlSnippets,
+ onClearSqlSnippets: state.clearSqlSnippets,
}}
- actions={[
- {
- label: 'Clear messages and refresh',
- onClick: () => {
- handleClearMessages()
- window.location.reload()
- },
- },
- ]}
- >
-
+ renderHeader={(props) => (
closeSidebar(SIDEBAR_KEYS.AI_ASSISTANT)}
- showMetadataWarning={showMetadataWarning}
- updatedOptInSinceMCP={updatedOptInSinceMCP}
- isHipaaProjectDisallowed={isHipaaProjectDisallowed}
- aiOptInLevel={aiOptInLevel}
/>
- {hasMessages ? (
-
-
- {renderedMessages}
- {error && (
- <>
-
- {isContextExceededError ? (
-
- ) : (
- <>
-
- }
- tooltip={{ content: { side: 'bottom', text: 'Clear messages' } }}
- />
- >
- )}
-
- }
- />
- >
- )}
- {isChatLoading && (
-
- )}
-
-
- The Assistant can make mistakes. Double check responses.
-
-
-
-
- ) : (
- setValue(val)}
- onFocusInput={() => inputRef.current?.focus()}
- />
- )}
-
-
- {editingMessageId && (
-
-
-
-
-
-
}
- onClick={cancelEdit}
- className="w-6 h-6 p-0"
- title="Cancel editing"
- aria-label="Cancel editing"
- tooltip={{
- content: { side: 'top', text:
},
- }}
- />
-
-
-
-
- )}
-
-
-
- {isSupportChat && !isSupportChatClosed && (
-
-
-
-
-
-
-
- )}
-
- {disablePrompts && (
-
- )}
-
- {isSuccess && !isApiKeySet && (
-
- }
- />
- )}
-
-
form>textarea]:text-base [&>form>textarea]:md:text-sm [&>form>textarea]:border',
- '[&>form>textarea]:rounded-md [&>form>textarea]:outline-hidden!',
- '[&>form>textarea]:ring-offset-0! [&>form>textarea]:ring-0!'
- )}
- loading={isChatLoading}
- isEditing={!!editingMessageId}
- disabled={isChatInputDisabled}
- placeholder={
- hasMessages
- ? isSupportChat
- ? 'Share details so the assistant can help with your support request...'
- : 'Ask a follow up question...'
- : (snap.sqlSnippets ?? [])?.length > 0
- ? 'Ask a question or make a change...'
- : isSupportChat
- ? 'Describe your support issue...'
- : 'Chat to Postgres...'
- }
- value={value}
- onValueChange={(e) => setValue(e.target.value)}
- onSubmit={(finalMessage) => {
- sendMessageToAssistant(finalMessage)
- }}
- onStop={() => {
- stop()
- // to save partial responses from the AI
- const lastMessage = chatMessages[chatMessages.length - 1]
- if (lastMessage && lastMessage.role === 'assistant') {
- state.updateMessage(lastMessage)
- }
- }}
- sqlSnippets={snap.sqlSnippets as SqlSnippet[] | undefined}
- onRemoveSnippet={(index) => {
- const newSnippets = [...(snap.sqlSnippets ?? [])]
- newSnippets.splice(index, 1)
- snap.setSqlSnippets(newSnippets)
- }}
- includeSnippetsInMessage={includeSnippetsInMessage}
- selectedModel={selectedModel}
- onSelectModel={(model) => snap.setModel(model)}
- />
-
-
-
+ )}
+ />
)
}
diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx
index e5631c81b38d0..11b87ad765386 100644
--- a/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx
@@ -24,9 +24,13 @@ import { useShortcut } from '@/state/shortcuts/useShortcut'
interface AIAssistantChatSelectorProps {
disabled?: boolean
+ shortcutsEnabled?: boolean
}
-export const AIAssistantChatSelector = ({ disabled = false }: AIAssistantChatSelectorProps) => {
+export const AIAssistantChatSelector = ({
+ disabled = false,
+ shortcutsEnabled = true,
+}: AIAssistantChatSelectorProps) => {
const snap = useAiAssistantStateSnapshot()
const [chatSelectorOpen, setChatSelectorOpen] = useState(false)
@@ -35,7 +39,13 @@ export const AIAssistantChatSelector = ({ disabled = false }: AIAssistantChatSel
const chats = Object.entries(snap.chats)
- useShortcut(SHORTCUT_IDS.AI_ASSISTANT_TOGGLE_HISTORY, () => setChatSelectorOpen((prev) => !prev))
+ useShortcut(
+ SHORTCUT_IDS.AI_ASSISTANT_TOGGLE_HISTORY,
+ () => setChatSelectorOpen((prev) => !prev),
+ {
+ enabled: shortcutsEnabled,
+ }
+ )
const handleSelectChat = (id: string) => {
snap.selectChat(id)
diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx
index 49351c8a205b4..c2f7294590ac5 100644
--- a/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx
@@ -33,6 +33,7 @@ import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
interface AIAssistantHeaderProps {
isChatLoading: boolean
+ shortcutsEnabled?: boolean
onNewChat: () => void
onCloseAssistant: () => void
showMetadataWarning: boolean
@@ -43,6 +44,7 @@ interface AIAssistantHeaderProps {
export const AIAssistantHeader = ({
isChatLoading,
+ shortcutsEnabled = true,
onNewChat,
onCloseAssistant,
showMetadataWarning,
@@ -87,15 +89,15 @@ export const AIAssistantHeader = ({
}
useShortcut(SHORTCUT_IDS.AI_ASSISTANT_COPY_CHAT_ID, handleCopyChatId, {
- enabled: !isChatLoading,
+ enabled: shortcutsEnabled && !isChatLoading,
})
useShortcut(SHORTCUT_IDS.AI_ASSISTANT_OPEN_PERMISSIONS, () => setIsOptInModalOpen(true), {
- enabled: !isChatLoading,
+ enabled: shortcutsEnabled && !isChatLoading,
})
useShortcut(SHORTCUT_IDS.AI_ASSISTANT_MAXIMIZE, toggleMaximise, {
- enabled: !isChatLoading,
+ enabled: shortcutsEnabled && !isChatLoading,
})
return (
@@ -128,7 +130,7 @@ export const AIAssistantHeader = ({
-
+
void
+ onClearSqlSnippets?: () => void
+}
+
+interface AssistantChatProps {
+ className?: string
+ chatId: string
+ shortcutsEnabled?: boolean
+ onNewChat: () => void
+ onSelectChat: (chatId: string) => void
+ onBranchChat: (messageId: string) => void
+ composerContext?: AssistantChatComposerContext
+ renderHeader?: (props: AssistantChatHeaderProps) => ReactNode
+}
+
+export const AssistantChat = ({
+ className,
+ chatId,
+ shortcutsEnabled = true,
+ onNewChat,
+ onSelectChat,
+ onBranchChat,
+ composerContext,
+ renderHeader,
+}: AssistantChatProps) => {
+ const { id: entityId } = useParams()
+ const { data: project } = useSelectedProjectQuery()
+ const searchParams = useSearchParamsShallow()
+
+ const { data: selectedOrganization, isPending: isLoadingOrganization } =
+ useSelectedOrganizationQuery()
+
+ const disablePrompts = useFlag('disableAssistantPrompts')
+ const snap = useAiAssistantStateSnapshot()
+ const state = useAiAssistantState()
+ const currentChat = snap.chats[chatId]
+
+ useShortcut(SHORTCUT_IDS.AI_ASSISTANT_CANCEL_EDIT, () => cancelEdit(), {
+ enabled: shortcutsEnabled,
+ })
+
+ const { hasAccess: hasAccessToAdvanceModel, isLoading: isLoadingEntitlements } =
+ useCheckEntitlements('assistant.advance_model')
+
+ const selectedModel = useMemo(() => {
+ // While entitlements are loading, use the stored model without enforcing access
+ if (isLoadingEntitlements) {
+ return snap.model ?? DEFAULT_ASSISTANT_BASE_MODEL_ID
+ }
+
+ const defaultModel = defaultAssistantModelId(hasAccessToAdvanceModel)
+ const model = snap.model ?? defaultModel
+
+ if (!isKnownAssistantModelId(model)) return defaultModel
+ if (!hasAccessToAdvanceModel && !isAssistantBaseModelId(model)) {
+ return DEFAULT_ASSISTANT_BASE_MODEL_ID
+ }
+
+ return model
+ }, [isLoadingEntitlements, hasAccessToAdvanceModel, snap.model])
+
+ const [updatedOptInSinceMCP] = useLocalStorageQuery(
+ LOCAL_STORAGE_KEYS.AI_ASSISTANT_MCP_OPT_IN,
+ false
+ )
+
+ const inputRef = useRef(null)
+
+ const { aiOptInLevel, isHipaaProjectDisallowed } = useOrgAiOptInLevel()
+ // Whether attached queries are sent at all. One definition, shared by the chat form
+ // (which folds them into the message text) and the message metadata (which states
+ // whether any of them was a logs query), so the two can't disagree.
+ const includeSnippetsInMessage = aiOptInLevel !== 'disabled'
+ const showMetadataWarning =
+ IS_PLATFORM &&
+ !!selectedOrganization &&
+ (aiOptInLevel === 'disabled' || aiOptInLevel === 'schema')
+
+ // Add a ref to store the last user message
+ const lastUserMessageRef = useRef(null)
+
+ const [value, setValue] = useState(composerContext?.initialInput || '')
+ const [editingMessageId, setEditingMessageId] = useState(null)
+ const [isResubmitting, setIsResubmitting] = useState(false)
+ const [messageRatings, setMessageRatings] = useState>({})
+
+ const { data: check, isSuccess } = useCheckOpenAIKeyQuery()
+ const isApiKeySet = !!check?.hasKey
+
+ const { mutateAsync: rateMessage } = useRateMessageMutation()
+
+ const { data: tables } = useTablesQuery(
+ {
+ projectRef: project?.ref,
+ connectionString: project?.connectionString,
+ schema: 'public',
+ },
+ { enabled: isApiKeySet }
+ )
+
+ const currentTable = tables?.find((t) => t.id.toString() === entityId)
+ const currentSchema = searchParams?.get('schema') ?? 'public'
+
+ // Update context in state
+ useEffect(() => {
+ state.setContext({
+ projectRef: project?.ref,
+ orgSlug: selectedOrganization?.slug,
+ connectionString: project?.connectionString ?? '',
+ })
+ }, [project?.ref, project?.connectionString, selectedOrganization?.slug, state])
+
+ const track = useTrack()
+
+ useEffect(() => {
+ state.ensureChatInstance(chatId)
+ }, [chatId, state])
+
+ const chatInstance = snap.chatInstances[chatId]
+
+ const {
+ messages: chatMessages,
+ status: chatStatus,
+ error,
+ sendMessage,
+ setMessages,
+ addToolApprovalResponse,
+ stop,
+ regenerate,
+ } = useChat({
+ id: chatId,
+ ...(chatInstance ? { chat: chatInstance } : {}),
+ sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
+ onError: onErrorChat,
+ })
+
+ const isChatLoading = chatStatus === 'submitted' || chatStatus === 'streaming'
+ const hasPendingApproval = hasPendingToolApproval(chatMessages)
+ const supportMetadata = currentChat?.supportMetadata
+ const isSupportChat = !!supportMetadata?.isSupportChat
+ const isSupportChatClosed = isSupportChat && supportMetadata.lifecycleStatus !== 'bot_active'
+ const supportConversationId = supportMetadata?.frontConversationId
+ const isChatInputDisabled =
+ !isApiKeySet || disablePrompts || isLoadingOrganization || isSupportChatClosed
+
+ const branchedFrom = currentChat?.branchedFrom
+ const branchedConversation = branchedFrom ? snap.chats[branchedFrom.chatId] : undefined
+
+ const deleteMessageFromHere = useCallback(
+ (messageId: string) => {
+ // Find the message index in current chatMessages
+ const messageIndex = chatMessages.findIndex((msg) => msg.id === messageId)
+ if (messageIndex === -1) return
+
+ if (isChatLoading) stop()
+
+ snap.deleteMessagesAfter(messageId, { includeSelf: true, chatId })
+
+ const updatedMessages = chatMessages.slice(0, messageIndex)
+ setMessages(updatedMessages)
+ },
+ [snap, setMessages, chatMessages, isChatLoading, stop, chatId]
+ )
+
+ const editMessage = useCallback(
+ (messageId: string) => {
+ const messageIndex = chatMessages.findIndex((msg) => msg.id === messageId)
+ if (messageIndex === -1) return
+
+ // Target message
+ const messageToEdit = chatMessages[messageIndex]
+
+ // Activate editing mode
+ setEditingMessageId(messageId)
+ const textContent =
+ messageToEdit.parts
+ ?.filter((part) => part.type === 'text')
+ .map((part) => part.text)
+ .join('') ?? ''
+ setValue(textContent)
+
+ setTimeout(() => {
+ if (inputRef.current) {
+ inputRef?.current?.focus()
+
+ // [Joshen] This is just to make the cursor go to the end of the text when focusing
+ const val = inputRef.current.value
+ inputRef.current.value = ''
+ inputRef.current.value = val
+ }
+ }, 100)
+ },
+ [chatMessages, setValue]
+ )
+
+ const cancelEdit = useCallback(() => {
+ setEditingMessageId(null)
+ setValue('')
+ }, [setValue])
+
+ const handleRateMessage = useCallback(
+ async (messageId: string, rating: 'positive' | 'negative', reason?: string) => {
+ if (!project?.ref || !selectedOrganization?.slug) return
+
+ // Optimistically update UI
+ setMessageRatings((prev) => ({ ...prev, [messageId]: rating }))
+
+ try {
+ const result = await rateMessage({
+ rating,
+ messages: chatMessages,
+ messageId,
+ projectRef: project.ref,
+ orgSlug: selectedOrganization.slug,
+ reason,
+ spanId: state.messageSpanIds[messageId],
+ })
+
+ track('assistant_message_rating_submitted', {
+ rating,
+ category: result.category,
+ ...(reason && { reason }),
+ chatId,
+ })
+ } catch (error) {
+ console.error('Failed to rate message:', error)
+ // Rollback on error
+ setMessageRatings((prev) => {
+ const { [messageId]: _, ...rest } = prev
+ return rest
+ })
+ }
+ },
+ [chatMessages, project?.ref, selectedOrganization?.slug, rateMessage, track, state, chatId]
+ )
+
+ const isContextExceededError =
+ error &&
+ (error.message?.includes('context_length_exceeded') ||
+ error.message?.includes('exceeds the context window'))
+
+ const renderedMessages = useMemo(
+ () =>
+ chatMessages.map((message, index) => {
+ const isBeingEdited = editingMessageId === message.id
+ const isAfterEditedMessage = editingMessageId
+ ? chatMessages.findIndex((m) => m.id === editingMessageId) < index
+ : false
+ const isLastMessage = index === chatMessages.length - 1
+
+ return (
+
+
+ {branchedConversation && branchedFrom?.messageId === message.id && (
+
+
+
+ Branched from
+
+
+
+
+ )}
+
+ )
+ }),
+ [
+ chatMessages,
+ deleteMessageFromHere,
+ editMessage,
+ cancelEdit,
+ editingMessageId,
+ chatStatus,
+ addToolApprovalResponse,
+ handleRateMessage,
+ messageRatings,
+ branchedConversation,
+ branchedFrom,
+ onSelectChat,
+ onBranchChat,
+ ]
+ )
+
+ const hasMessages = chatMessages.length > 0
+
+ const sendMessageToAssistant = (finalContent: string) => {
+ if (editingMessageId) {
+ // Handling when the user is in edit mode
+ // delete the message(s) from the chat just like the delete button
+ setIsResubmitting(true)
+ deleteMessageFromHere(editingMessageId)
+ setEditingMessageId(null)
+ }
+
+ // Read off the attachments this message actually carries, so detaching the
+ // "Current Query" chip also drops the claim. Gated on the same condition that
+ // decides whether attachments make it into the text at all: with AI opt-in
+ // disabled the chip is shown but no query is sent, and claiming otherwise would
+ // have the server prepend ClickHouse context for a message holding no query.
+ // Rides on the message rather than the request, so a Retry reproduces the context
+ // the message was asked in.
+ const metadata: AssistantMessageMetadata = {
+ containsLogsSnippets:
+ includeSnippetsInMessage && containsLogsSnippets(composerContext?.sqlSnippets),
+ }
+
+ const payload = {
+ role: 'user',
+ createdAt: new Date(),
+ parts: [{ type: 'text', text: finalContent }],
+ id: uuidv4(),
+ metadata,
+ } as MessageType
+
+ composerContext?.onClearSqlSnippets?.()
+ lastUserMessageRef.current = payload
+ if (hasPendingApproval && !editingMessageId) {
+ setMessages(resolvePendingToolApprovalsAsDenied(chatMessages))
+ }
+ sendMessage(payload, {
+ body: {
+ schema: currentSchema,
+ table: currentTable?.name,
+ },
+ })
+ setValue('')
+
+ if (finalContent.includes('Help me to debug')) {
+ track('assistant_debug_submitted', { chatId })
+ } else {
+ track('assistant_prompt_submitted', { chatId })
+ }
+ }
+
+ const handleClearMessages = () => {
+ if (isChatLoading) stop()
+ snap.clearMessages(chatId)
+ setMessages([])
+ lastUserMessageRef.current = null
+ setEditingMessageId(null)
+ }
+
+ useEffect(() => {
+ // Keep "Thinking" visible while stopping and resubmitting during edit
+ // Only clear once the new response actually starts streaming (or errors)
+ if (isResubmitting && (chatStatus === 'streaming' || !!error)) {
+ setIsResubmitting(false)
+ }
+ }, [isResubmitting, chatStatus, error])
+
+ useEffect(() => {
+ // Approval-required tools can't run in parallel. Auto-deny extras so the model reissues them sequentially.
+ for (const id of getParallelApprovalIdsToReject(chatMessages)) {
+ addToolApprovalResponse?.({
+ id,
+ approved: false,
+ reason:
+ 'Only one approval-required tool call is allowed per turn. Please reissue this tool call after the current one completes.',
+ })
+ }
+ }, [chatMessages, addToolApprovalResponse])
+
+ useEffect(() => {
+ setValue(composerContext?.initialInput || '')
+ if (inputRef.current && composerContext?.initialInput) {
+ inputRef.current.focus()
+ inputRef.current.setSelectionRange(
+ composerContext.initialInput.length,
+ composerContext.initialInput.length
+ )
+ }
+ }, [composerContext?.initialInput])
+
+ return (
+ {
+ handleClearMessages()
+ window.location.reload()
+ },
+ },
+ ]}
+ >
+
+ {renderHeader?.({
+ isChatLoading,
+ showMetadataWarning,
+ updatedOptInSinceMCP,
+ isHipaaProjectDisallowed,
+ aiOptInLevel,
+ })}
+ {hasMessages ? (
+
+
+ {renderedMessages}
+ {error && (
+ <>
+
+ {isContextExceededError ? (
+
+ ) : (
+ <>
+
+ }
+ tooltip={{ content: { side: 'bottom', text: 'Clear messages' } }}
+ />
+ >
+ )}
+
+ }
+ />
+ >
+ )}
+ {isChatLoading && (
+
+ )}
+
+
+ The Assistant can make mistakes. Double check responses.
+
+
+
+
+ ) : (
+ setValue(val)}
+ onFocusInput={() => inputRef.current?.focus()}
+ />
+ )}
+
+
+ {editingMessageId && (
+
+
+
+
+
+
}
+ onClick={cancelEdit}
+ className="w-6 h-6 p-0"
+ title="Cancel editing"
+ aria-label="Cancel editing"
+ tooltip={{
+ content: { side: 'top', text:
},
+ }}
+ />
+
+
+
+
+ )}
+
+
+
+ {isSupportChat && !isSupportChatClosed && (
+
+
+
+
+
+
+
+ )}
+
+ {disablePrompts && (
+
+ )}
+
+ {isSuccess && !isApiKeySet && (
+
+ }
+ />
+ )}
+
+
form>textarea]:text-base [&>form>textarea]:md:text-sm [&>form>textarea]:border',
+ '[&>form>textarea]:rounded-md [&>form>textarea]:outline-hidden!',
+ '[&>form>textarea]:ring-offset-0! [&>form>textarea]:ring-0!'
+ )}
+ loading={isChatLoading}
+ isEditing={!!editingMessageId}
+ disabled={isChatInputDisabled}
+ placeholder={
+ hasMessages
+ ? isSupportChat
+ ? 'Share details so the assistant can help with your support request...'
+ : 'Ask a follow up question...'
+ : (composerContext?.sqlSnippets ?? []).length > 0
+ ? 'Ask a question or make a change...'
+ : isSupportChat
+ ? 'Describe your support issue...'
+ : 'Chat to Postgres...'
+ }
+ value={value}
+ onValueChange={(e) => setValue(e.target.value)}
+ onSubmit={(finalMessage) => {
+ sendMessageToAssistant(finalMessage)
+ }}
+ onStop={() => {
+ stop()
+ // to save partial responses from the AI
+ const lastMessage = chatMessages[chatMessages.length - 1]
+ if (lastMessage && lastMessage.role === 'assistant') {
+ state.updateMessage(lastMessage, chatId)
+ }
+ }}
+ sqlSnippets={composerContext?.sqlSnippets}
+ onRemoveSnippet={(index) => {
+ const newSnippets = [...(composerContext?.sqlSnippets ?? [])]
+ newSnippets.splice(index, 1)
+ composerContext?.onSetSqlSnippets?.(newSnippets)
+ }}
+ includeSnippetsInMessage={includeSnippetsInMessage}
+ selectedModel={selectedModel}
+ onSelectModel={(model) => snap.setModel(model)}
+ />
+
+
+
+ )
+}
diff --git a/apps/studio/components/ui/AIAssistantPanel/Message.Context.tsx b/apps/studio/components/ui/AIAssistantPanel/Message.Context.tsx
index 3ce0cb1dd57cf..d39824361ee19 100644
--- a/apps/studio/components/ui/AIAssistantPanel/Message.Context.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/Message.Context.tsx
@@ -26,6 +26,7 @@ export interface MessageActions {
onDelete: (id: string) => void
onEdit: (id: string) => void
+ onBranch: (id: string) => void
onCancelEdit: () => void
onRate?: (id: string, rating: 'positive' | 'negative', reason?: string) => void
}
diff --git a/apps/studio/components/ui/AIAssistantPanel/Message.tsx b/apps/studio/components/ui/AIAssistantPanel/Message.tsx
index c9a5ef5e6e530..6ec5780bec6c6 100644
--- a/apps/studio/components/ui/AIAssistantPanel/Message.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/Message.tsx
@@ -8,11 +8,9 @@ import { MessageActions } from './Message.Actions'
import type { AddToolApprovalResponse, MessageInfo } from './Message.Context'
import { MessageProvider, useMessageActionsContext, useMessageInfoContext } from './Message.Context'
import { MessageDisplay } from './Message.Display'
-import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
function AssistantMessage({ message }: { message: VercelMessage }) {
- const snap = useAiAssistantStateSnapshot()
- const { onCancelEdit, onRate } = useMessageActionsContext()
+ const { onBranch, onCancelEdit, onRate } = useMessageActionsContext()
const { id, variant, state, isLastMessage, readOnly, rating, isLoading } = useMessageInfoContext()
const handleRate = (newRating: 'positive' | 'negative', reason?: string) => {
@@ -51,7 +49,7 @@ function AssistantMessage({ message }: { message: VercelMessage }) {
isActive={rating === 'negative'}
disabled={!!rating}
/>
-
snap.branchChat(id)} />
+ onBranch(id)} />
)}
@@ -107,6 +105,7 @@ interface MessageProps {
addToolApprovalResponse?: AddToolApprovalResponse
onDelete: (id: string) => void
onEdit: (id: string) => void
+ onBranch: (id: string) => void
isAfterEditedMessage: boolean
isBeingEdited: boolean
onCancelEdit: () => void
@@ -139,6 +138,7 @@ export function Message(props: MessageProps) {
addToolApprovalResponse: props.addToolApprovalResponse,
onDelete: props.onDelete,
onEdit: props.onEdit,
+ onBranch: props.onBranch,
onCancelEdit: props.onCancelEdit,
onRate: props.onRate,
}
diff --git a/apps/studio/state/ai-assistant-state.test.ts b/apps/studio/state/ai-assistant-state.test.ts
index 4fb412ffe831f..d4670010878f5 100644
--- a/apps/studio/state/ai-assistant-state.test.ts
+++ b/apps/studio/state/ai-assistant-state.test.ts
@@ -1,7 +1,7 @@
import { proxy, ref } from 'valtio/vanilla'
import { describe, expect, it } from 'vitest'
-import { sanitizeForCloning } from './ai-assistant-state'
+import { createAiAssistantState, sanitizeForCloning } from './ai-assistant-state'
describe('AI assistant chat message sync', () => {
// FE-3954: syncing the live array into valtio corrupted it with Proxies, breaking structuredClone in addToolApprovalResponse
@@ -44,3 +44,82 @@ describe('AI assistant chat message sync', () => {
expect(() => structuredClone(replacedMessage)).not.toThrow()
})
})
+
+describe('AI assistant chat surface isolation', () => {
+ it('creates chats without changing the sidebar selection', () => {
+ const state = createAiAssistantState()
+ const sidebarChatId = state.newChat({ name: 'Sidebar chat' })
+
+ const explorerChatId = state.createChat({ name: 'Explorer chat' })
+
+ expect(explorerChatId).not.toBe(sidebarChatId)
+ expect(state.activeChatId).toBe(sidebarChatId)
+ expect(state.chats[explorerChatId]?.name).toBe('Explorer chat')
+ })
+
+ it('branches a specified chat without changing the sidebar selection', () => {
+ const state = createAiAssistantState()
+ const sidebarChatId = state.newChat({ name: 'Sidebar chat' })
+ const explorerChatId = state.createChat({ name: 'Explorer chat' })
+ state.chats[explorerChatId].messages = [
+ { id: 'message-1', role: 'user', parts: [{ type: 'text', text: 'Hello' }] },
+ ]
+
+ const branchId = state.createBranch(explorerChatId, 'message-1')
+
+ expect(branchId).toBeDefined()
+ expect(state.activeChatId).toBe(sidebarChatId)
+ expect(state.chats[branchId!]?.branchedFrom).toEqual({
+ chatId: explorerChatId,
+ messageId: 'message-1',
+ })
+ })
+
+ it('mutates an explicit chat without changing or clearing the sidebar chat', () => {
+ const state = createAiAssistantState()
+ const sidebarChatId = state.newChat({ name: 'Sidebar chat' })
+ const explorerChatId = state.createChat({ name: 'Explorer chat' })
+ state.chats[sidebarChatId].messages = [
+ { id: 'sidebar-message', role: 'user', parts: [{ type: 'text', text: 'Keep me' }] },
+ ]
+ state.chats[explorerChatId].messages = [
+ { id: 'explorer-message', role: 'user', parts: [{ type: 'text', text: 'Clear me' }] },
+ ]
+ state.chatInstances[explorerChatId].messages = [
+ { id: 'explorer-message', role: 'user', parts: [{ type: 'text', text: 'Clear me' }] },
+ ]
+
+ state.clearMessages(explorerChatId)
+
+ expect(state.activeChatId).toBe(sidebarChatId)
+ expect(state.chats[sidebarChatId].messages).toHaveLength(1)
+ expect(state.chats[explorerChatId].messages).toHaveLength(0)
+ expect(state.chatInstances[explorerChatId].messages).toHaveLength(0)
+ })
+
+ it('keeps explicit chat message edits synchronized with the live chat instance', () => {
+ const state = createAiAssistantState()
+ const chatId = state.createChat({ name: 'Explorer chat' })
+ const messages = [
+ { id: 'message-1', role: 'user' as const, parts: [{ type: 'text' as const, text: 'First' }] },
+ {
+ id: 'message-2',
+ role: 'user' as const,
+ parts: [{ type: 'text' as const, text: 'Second' }],
+ },
+ ]
+ state.chats[chatId].messages = messages
+ state.chatInstances[chatId].messages = messages
+
+ state.deleteMessagesAfter('message-2', { chatId })
+ state.updateMessage(
+ { id: 'message-1', role: 'user', parts: [{ type: 'text', text: 'Updated' }] },
+ chatId
+ )
+
+ expect(state.chats[chatId].messages).toEqual([
+ { id: 'message-1', role: 'user', parts: [{ type: 'text', text: 'Updated' }] },
+ ])
+ expect(state.chatInstances[chatId].messages).toEqual(state.chats[chatId].messages)
+ })
+})
diff --git a/apps/studio/state/ai-assistant-state.tsx b/apps/studio/state/ai-assistant-state.tsx
index 5355074cf655c..8e0413bbc46a6 100644
--- a/apps/studio/state/ai-assistant-state.tsx
+++ b/apps/studio/state/ai-assistant-state.tsx
@@ -60,7 +60,7 @@ export type SupportChatMetadata = {
isLifecycleSyncing: boolean
}
-type ChatSession = {
+export type ChatSession = {
id: string
name: string
messages: AssistantMessageType[]
@@ -87,6 +87,10 @@ type AiAssistantData = {
context: AiAssistantContext
}
+type CreateChatOptions = { name?: string; initialMessage?: string }
+type NewChatOptions = CreateChatOptions &
+ Partial>
+
// Data structure stored in IndexedDB
type StoredAiAssistantState = {
projectRef: string
@@ -389,11 +393,7 @@ export const createAiAssistantState = (): AiAssistantState => {
return state.activeChatId ? state.chats[state.activeChatId] : undefined
},
- newChat: (
- options?: { name?: string; initialMessage?: string } & Partial<
- Pick
- >
- ) => {
+ createChat: (options?: CreateChatOptions) => {
const chatId = uuidv4()
const newChat: ChatSession = {
id: chatId,
@@ -407,21 +407,23 @@ export const createAiAssistantState = (): AiAssistantState => {
...state.chats,
[chatId]: newChat,
}
- state.activeChatId = chatId
- // Create new chat instance
const chatInstance = createChatInstance(state, { id: chatId, initialMessages: [] })
-
state.chatInstances[chatId] = ref(chatInstance)
- // If initialMessage is provided, append it to the chat instance
if (options?.initialMessage) {
chatInstance.sendMessage({
text: options.initialMessage,
})
}
- // Update non-chat related state based on options, falling back to current state, then initial
+ return chatId
+ },
+
+ newChat: (options?: NewChatOptions) => {
+ const chatId = state.createChat(options)
+ state.selectChat(chatId)
+
const initialAiAssistantData = createInitialAiAssistantData()
state.initialInput = options?.initialInput ?? initialAiAssistantData.initialInput
state.sqlSnippets = options?.sqlSnippets ?? initialAiAssistantData.sqlSnippets
@@ -431,8 +433,8 @@ export const createAiAssistantState = (): AiAssistantState => {
return chatId
},
- branchChat: (messageId: string) => {
- const sourceChat = state.activeChat
+ createBranch: (sourceChatId: string, messageId: string) => {
+ const sourceChat = state.chats[sourceChatId]
if (!sourceChat) return
const messageIndex = sourceChat.messages.findIndex((msg) => msg.id === messageId)
@@ -456,12 +458,22 @@ export const createAiAssistantState = (): AiAssistantState => {
...state.chats,
[chatId]: newChat,
}
- state.activeChatId = chatId
state.chatInstances[chatId] = ref(
createChatInstance(state, { id: chatId, initialMessages: branchedMessages })
)
+ return chatId
+ },
+
+ branchChat: (messageId: string) => {
+ if (!state.activeChatId) return
+
+ const chatId = state.createBranch(state.activeChatId, messageId)
+ if (!chatId) return
+
+ state.selectChat(chatId)
+
const initialAiAssistantData = createInitialAiAssistantData()
state.initialInput = initialAiAssistantData.initialInput
state.sqlSnippets = initialAiAssistantData.sqlSnippets
@@ -493,35 +505,33 @@ export const createAiAssistantState = (): AiAssistantState => {
})
},
- selectChat: (id: string) => {
- if (id !== state.activeChatId) {
- state.activeChatId = id
- const chat = state.chats[id]
- if (chat) {
- if (!state.chatInstances[id]) {
- state.chatInstances[id] = ref(
- createChatInstance(state, { id, initialMessages: chat.messages })
- )
- }
- }
+ ensureChatInstance: (id: string) => {
+ const chat = state.chats[id]
+ if (chat && !state.chatInstances[id]) {
+ state.chatInstances[id] = ref(
+ createChatInstance(state, { id, initialMessages: chat.messages })
+ )
}
},
+ selectChat: (id: string) => {
+ if (!state.chats[id]) return
+
+ state.activeChatId = id
+ state.ensureChatInstance(id)
+ },
+
deleteChat: (id: string) => {
const { [id]: _, ...remainingChats } = state.chats
state.chats = remainingChats
+ delete state.chatInstances[id]
if (id === state.activeChatId) {
const remainingChatIds = Object.keys(remainingChats)
state.activeChatId = remainingChatIds.length > 0 ? remainingChatIds[0] : undefined
if (state.activeChatId) {
- const chat = state.chats[state.activeChatId]
- if (!state.chatInstances[state.activeChatId]) {
- state.chatInstances[state.activeChatId] = ref(
- createChatInstance(state, { id: state.activeChatId, initialMessages: chat.messages })
- )
- }
+ state.ensureChatInstance(state.activeChatId)
}
}
},
@@ -534,19 +544,27 @@ export const createAiAssistantState = (): AiAssistantState => {
}
},
- clearMessages: () => {
- const chat = state.activeChat
+ clearMessages: (chatId = state.activeChatId) => {
+ if (!chatId) return
+
+ const chat = state.chats[chatId]
if (chat) {
chat.messages = []
+ const chatInstance = state.chatInstances[chatId]
+ if (chatInstance) chatInstance.messages = []
chat.updatedAt = new Date()
- state.suggestions = undefined
- state.sqlSnippets = []
- state.initialInput = ''
+ if (chatId === state.activeChatId) {
+ state.suggestions = undefined
+ state.sqlSnippets = []
+ state.initialInput = ''
+ }
}
},
- deleteMessagesAfter: (id: string, { includeSelf = true } = {}) => {
- const chat = state.activeChat
+ deleteMessagesAfter: (id: string, { includeSelf = true, chatId = state.activeChatId } = {}) => {
+ if (!chatId) return
+
+ const chat = state.chats[chatId]
if (!chat) return
const messageIndex = chat.messages.findIndex((msg) => msg.id === id)
@@ -555,17 +573,37 @@ export const createAiAssistantState = (): AiAssistantState => {
// Delete all messages from the target message (optionally including) to the end
const startIndex = includeSelf ? messageIndex : messageIndex + 1
chat.messages.splice(startIndex)
+ const chatInstance = state.chatInstances[chatId]
+ const instanceMessageIndex = chatInstance?.messages.findIndex((message) => message.id === id)
+ if (chatInstance && instanceMessageIndex !== undefined && instanceMessageIndex !== -1) {
+ chatInstance.messages = chatInstance.messages.slice(
+ 0,
+ includeSelf ? instanceMessageIndex : instanceMessageIndex + 1
+ )
+ }
chat.updatedAt = new Date()
},
- updateMessage: (updatedMessage: MessageType) => {
- const chat = state.activeChat
+ updateMessage: (updatedMessage: MessageType, chatId = state.activeChatId) => {
+ if (!chatId) return
+
+ const chat = state.chats[chatId]
if (!chat) return
const messageIndex = chat.messages.findIndex((msg) => msg.id === updatedMessage.id)
if (messageIndex !== -1) {
// Clone first — valtio's proxy() mutates nested properties in place and would corrupt the SDK's live array
- chat.messages[messageIndex] = sanitizeForCloning(updatedMessage)
+ const clonedMessage = sanitizeForCloning(updatedMessage)
+ chat.messages[messageIndex] = clonedMessage
+ const chatInstance = state.chatInstances[chatId]
+ const instanceMessageIndex = chatInstance?.messages.findIndex(
+ (message) => message.id === updatedMessage.id
+ )
+ if (chatInstance && instanceMessageIndex !== undefined && instanceMessageIndex !== -1) {
+ chatInstance.messages = chatInstance.messages.map((message, index) =>
+ index === instanceMessageIndex ? sanitizeForCloning(updatedMessage) : message
+ )
+ }
chat.updatedAt = new Date()
}
},
@@ -620,18 +658,7 @@ export const createAiAssistantState = (): AiAssistantState => {
}
// Initialize chat instance for the active chat
- if (
- state.activeChatId &&
- state.chats[state.activeChatId] &&
- !state.chatInstances[state.activeChatId]
- ) {
- state.chatInstances[state.activeChatId] = ref(
- createChatInstance(state, {
- id: state.activeChatId,
- initialMessages: state.chats[state.activeChatId].messages,
- })
- )
- }
+ if (state.activeChatId) state.ensureChatInstance(state.activeChatId)
},
clearStorage: async () => {
@@ -650,19 +677,18 @@ export type AiAssistantState = AiAssistantData & {
messageSpanIds: Record
setContext: (context: Partial) => void
setModel: (model: AssistantModel) => void
- newChat: (
- options?: { name?: string; initialMessage?: string } & Partial<
- Pick
- >
- ) => string
+ createChat: (options?: CreateChatOptions) => string
+ newChat: (options?: NewChatOptions) => string
+ createBranch: (sourceChatId: string, messageId: string) => string | undefined
branchChat: (messageId: string) => string | undefined
setSupportLifecycleStatus: (chatId: string, status: AiSupportStatus) => void
+ ensureChatInstance: (id: string) => void
selectChat: (id: string) => void
deleteChat: (id: string) => void
renameChat: (id: string, name: string) => void
- clearMessages: () => void
- deleteMessagesAfter: (id: string, options?: { includeSelf?: boolean }) => void
- updateMessage: (message: MessageType) => void
+ clearMessages: (chatId?: string) => void
+ deleteMessagesAfter: (id: string, options?: { includeSelf?: boolean; chatId?: string }) => void
+ updateMessage: (message: MessageType, chatId?: string) => void
setSqlSnippets: (snippets: SqlSnippet[]) => void
clearSqlSnippets: () => void
loadPersistedState: (persistedState: StoredAiAssistantState) => void
From b5477a89a3fb12840cc44046825cda4390b2f14c Mon Sep 17 00:00:00 2001
From: Ivan Vasilov
Date: Thu, 13 Aug 2026 09:48:13 +0200
Subject: [PATCH 3/6] chore: Update API types (#48981)
Update the API types by running `api:codegen`. Some of the changes are
fixed in code, some of the type changes had to be reverted (JIT Access,
SSO features).
## Summary by CodeRabbit
* **Billing**
* Updated subscription messaging to reflect AWS Marketplace billing.
* Removed outdated partner-billing downgrade notices.
* **Bug Fixes**
* Improved request handling for API keys, custom domains, SQL snippets,
branches, and storage operations.
* Improved legacy signing-key compatibility.
* Refined temporary database access availability messaging.
* **Updates**
* Removed Fly as an available cloud provider for region selection.
---
.../Subscription/DowngradeModal.tsx | 6 -
.../SubscriptionPlanUpdateDialog.tsx | 8 -
.../JitDbAccess.utils.test.ts | 2 +
.../JitDbAccessConfiguration.tsx | 23 +-
.../data/api-keys/api-key-create-mutation.ts | 4 +-
.../data/api-keys/api-key-delete-mutation.ts | 2 +-
apps/studio/data/api-keys/api-key-id-query.ts | 2 +-
apps/studio/data/api-keys/api-keys-query.ts | 2 +-
.../legacy-api-key-toggle-mutation.ts | 2 +-
.../studio/data/branches/branch-diff-query.ts | 5 +-
.../studio/data/content/sql-snippets-query.ts | 2 +-
.../custom-domains-delete-mutation.ts | 2 +-
.../organization-available-regions-query.ts | 2 +-
...iceberg-namespace-table-delete-mutation.ts | 2 +-
.../lib/api/self-hosted/signing-keys.test.ts | 1 +
.../lib/api/self-hosted/signing-keys.ts | 1 +
.../[slug]/billing/subscription.ts | 2 +-
.../InviteMemberButton.network.test.tsx | 1 +
.../UpdateRolesPanel.network.test.tsx | 1 +
packages/api-types/types/api.d.ts | 746 +++-
packages/api-types/types/platform.d.ts | 3675 +++++++++++------
21 files changed, 3141 insertions(+), 1350 deletions(-)
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/DowngradeModal.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/DowngradeModal.tsx
index 5b4dd4f5ed970..13160f9235c62 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/DowngradeModal.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/DowngradeModal.tsx
@@ -170,12 +170,6 @@ export const DowngradeModal = ({
-
- {subscription?.billing_via_partner === true && subscription.billing_partner === 'fly' && (
-
- Your organization will be downgraded at the end of your current billing cycle.
-
- )}
- {billingViaPartner &&
- billingPartner === 'fly' &&
- subscriptionPreview?.plan_change_type === 'downgrade' && (
-
- Your organization will be downgraded at the end of your current billing
- cycle.
-
- )}
)}
diff --git a/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccess.utils.test.ts b/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccess.utils.test.ts
index edcdee317cdc9..9857f1069a661 100644
--- a/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccess.utils.test.ts
+++ b/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccess.utils.test.ts
@@ -121,6 +121,7 @@ describe('getJitMemberOptions', () => {
const organizationMembers: OrganizationMembersData = [
{
gotrue_id: 'de305d54-75b4-431b-adb2-eb6b9e546014',
+ avatar_url: null,
primary_email: 'active@example.com',
username: 'Active User',
is_sso_user: false,
@@ -130,6 +131,7 @@ describe('getJitMemberOptions', () => {
},
{
gotrue_id: '',
+ avatar_url: null,
invited_id: 123,
invited_at: '2026-03-01T00:00:00.000Z',
primary_email: 'expired-invite@example.com',
diff --git a/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccessConfiguration.tsx b/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccessConfiguration.tsx
index f6dd58a29073a..dab3b686cd3cd 100644
--- a/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccessConfiguration.tsx
+++ b/apps/studio/components/interfaces/Settings/Database/JitDatabaseAccess/JitDbAccessConfiguration.tsx
@@ -318,19 +318,15 @@ export const JitDbAccessConfiguration = () => {
const unavailableTitle =
unavailableReason === 'postgres_upgrade_required'
? 'Postgres upgrade required'
- : unavailableReason === 'manual_migration_required'
- ? 'Migration required'
- : unavailableReason === 'ssl_enforcement_required'
- ? 'SSL enforcement required'
- : 'Temporary access unavailable'
+ : unavailableReason === 'ssl_enforcement_required'
+ ? 'SSL enforcement required'
+ : 'Temporary access unavailable'
const unavailableDescription =
unavailableReason === 'postgres_upgrade_required'
? 'must be upgraded to Postgres 17 or later before temporary access can be enabled.'
- : unavailableReason === 'manual_migration_required'
- ? 'must be migrated before temporary access can be enabled. Contact support to migrate this project.'
- : unavailableReason === 'ssl_enforcement_required'
- ? 'must have SSL enforcement enabled before temporary access can be enabled.'
- : 'This feature is currently unavailable for this project. Contact support if you need help enabling it.'
+ : unavailableReason === 'ssl_enforcement_required'
+ ? 'must have SSL enforcement enabled before temporary access can be enabled.'
+ : 'This feature is currently unavailable for this project. Contact support if you need help enabling it.'
useEffect(() => {
if (!isLoadingConfiguration && jitDbAccessConfiguration) {
@@ -386,12 +382,13 @@ export const JitDbAccessConfiguration = () => {
layout="responsive"
title={unavailableTitle}
description={
- unavailableReason === 'temporarily_unavailable' ? (
- unavailableDescription
- ) : (
+ unavailableReason === 'postgres_upgrade_required' ||
+ unavailableReason === 'ssl_enforcement_required' ? (
<>
{projectReference} {unavailableDescription}
>
+ ) : (
+ unavailableDescription
)
}
actions={
diff --git a/apps/studio/data/api-keys/api-key-create-mutation.ts b/apps/studio/data/api-keys/api-key-create-mutation.ts
index 1aa32df38b210..3e07cfe8020af 100644
--- a/apps/studio/data/api-keys/api-key-create-mutation.ts
+++ b/apps/studio/data/api-keys/api-key-create-mutation.ts
@@ -18,7 +18,7 @@ export async function createAPIKey(payload: APIKeyCreateVariables) {
params: {
path: { ref: payload.projectRef },
query: {
- reveal: false,
+ reveal: 'false',
},
},
body: {
@@ -29,7 +29,7 @@ export async function createAPIKey(payload: APIKeyCreateVariables) {
role: 'service_role',
},
}
- : name),
+ : {}),
type: payload.type,
name: payload.name,
diff --git a/apps/studio/data/api-keys/api-key-delete-mutation.ts b/apps/studio/data/api-keys/api-key-delete-mutation.ts
index 18d0e767c4f1e..10fb0eabff918 100644
--- a/apps/studio/data/api-keys/api-key-delete-mutation.ts
+++ b/apps/studio/data/api-keys/api-key-delete-mutation.ts
@@ -16,7 +16,7 @@ export async function deleteAPIKey(payload: APIKeyDeleteVariables) {
const { data, error } = await del('/v1/projects/{ref}/api-keys/{id}', {
params: {
path: { ref: payload.projectRef, id: payload.id },
- query: { reveal: false },
+ query: { reveal: 'false' },
},
})
diff --git a/apps/studio/data/api-keys/api-key-id-query.ts b/apps/studio/data/api-keys/api-key-id-query.ts
index 9149361f40194..7340bafe0695d 100644
--- a/apps/studio/data/api-keys/api-key-id-query.ts
+++ b/apps/studio/data/api-keys/api-key-id-query.ts
@@ -16,7 +16,7 @@ export async function getAPIKeysById(
const { data, error } = await get('/v1/projects/{ref}/api-keys/{id}', {
params: {
path: { ref: projectRef, id },
- query: { reveal },
+ query: { reveal: reveal ? 'true' : 'false' },
},
signal,
})
diff --git a/apps/studio/data/api-keys/api-keys-query.ts b/apps/studio/data/api-keys/api-keys-query.ts
index a9f87625e3878..5ce1f14441741 100644
--- a/apps/studio/data/api-keys/api-keys-query.ts
+++ b/apps/studio/data/api-keys/api-keys-query.ts
@@ -55,7 +55,7 @@ async function getAPIKeys({ projectRef, reveal }: APIKeysVariables, signal?: Abo
if (!projectRef) throw new Error('projectRef is required')
const { data, error } = await get(`/v1/projects/{ref}/api-keys`, {
- params: { path: { ref: projectRef }, query: { reveal } },
+ params: { path: { ref: projectRef }, query: { reveal: reveal ? 'true' : 'false' } },
signal,
})
diff --git a/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts b/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts
index 72799e7686afc..cc4c0849c7124 100644
--- a/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts
+++ b/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts
@@ -16,7 +16,7 @@ export async function toggleLegacyAPIKeys(payload: ToggleLegacyAPIKeysVariables)
const { data, error } = await put('/v1/projects/{ref}/api-keys/legacy', {
params: {
path: { ref: payload.projectRef },
- query: { enabled: payload.enabled },
+ query: { enabled: payload.enabled ? 'true' : 'false' },
},
})
diff --git a/apps/studio/data/branches/branch-diff-query.ts b/apps/studio/data/branches/branch-diff-query.ts
index a858a48a3a4d8..4719993ac9cbe 100644
--- a/apps/studio/data/branches/branch-diff-query.ts
+++ b/apps/studio/data/branches/branch-diff-query.ts
@@ -24,10 +24,7 @@ export async function getBranchDiff({
const { data: diffData, error } = await get('/v1/branches/{branch_id_or_ref}/diff', {
params: {
path: { branch_id_or_ref: branchRef },
- query:
- Object.keys(query).length > 0
- ? (query as { included_schemas?: string; pgdelta?: boolean })
- : undefined,
+ query: Object.keys(query).length > 0 ? query : undefined,
},
headers: {
Accept: 'text/plain',
diff --git a/apps/studio/data/content/sql-snippets-query.ts b/apps/studio/data/content/sql-snippets-query.ts
index ec554a92b0c43..dbc4643479dad 100644
--- a/apps/studio/data/content/sql-snippets-query.ts
+++ b/apps/studio/data/content/sql-snippets-query.ts
@@ -40,7 +40,7 @@ export async function getSqlSnippets(
type,
cursor,
visibility,
- favorite,
+ favorite: favorite?.toString(),
name,
limit: SNIPPET_PAGE_LIMIT.toString(),
sort_by: sort,
diff --git a/apps/studio/data/custom-domains/custom-domains-delete-mutation.ts b/apps/studio/data/custom-domains/custom-domains-delete-mutation.ts
index 9d88c477b7f9d..56da08a1e1595 100644
--- a/apps/studio/data/custom-domains/custom-domains-delete-mutation.ts
+++ b/apps/studio/data/custom-domains/custom-domains-delete-mutation.ts
@@ -18,7 +18,7 @@ export async function deleteCustomDomain({
const { data, error } = await del(`/v1/projects/{ref}/custom-hostname`, {
params: {
path: { ref: projectRef },
- query: { remove_addon: removeAddon },
+ query: { remove_addon: removeAddon ? 'true' : 'false' },
},
})
diff --git a/apps/studio/data/organizations/organization-available-regions-query.ts b/apps/studio/data/organizations/organization-available-regions-query.ts
index 0c7ec9ec51b8d..2dbb1a9154213 100644
--- a/apps/studio/data/organizations/organization-available-regions-query.ts
+++ b/apps/studio/data/organizations/organization-available-regions-query.ts
@@ -10,7 +10,7 @@ export type DesiredInstanceSizeForAvailableRegions =
export type OrganizationAvailableRegionsVariables = {
slug?: string
- cloudProvider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ cloudProvider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
desiredInstanceSize?: DesiredInstanceSizeForAvailableRegions
}
diff --git a/apps/studio/data/storage/iceberg-namespace-table-delete-mutation.ts b/apps/studio/data/storage/iceberg-namespace-table-delete-mutation.ts
index d14f52fca5c3e..d78bd1d7678a0 100644
--- a/apps/studio/data/storage/iceberg-namespace-table-delete-mutation.ts
+++ b/apps/studio/data/storage/iceberg-namespace-table-delete-mutation.ts
@@ -25,7 +25,7 @@ async function deleteIcebergNamespaceTable({
{
params: {
path: { ref: projectRef, id: warehouse, namespace, table },
- query: { purge: true },
+ query: { purge: 'true' },
},
}
)
diff --git a/apps/studio/lib/api/self-hosted/signing-keys.test.ts b/apps/studio/lib/api/self-hosted/signing-keys.test.ts
index 69493f6509f7c..8e06231cb9068 100644
--- a/apps/studio/lib/api/self-hosted/signing-keys.test.ts
+++ b/apps/studio/lib/api/self-hosted/signing-keys.test.ts
@@ -30,6 +30,7 @@ describe('api/self-hosted/signing-keys', () => {
expect(key).toEqual({
id: '00000000-0000-0000-0000-000000000000',
algorithm: 'HS256',
+ public_jwk: '',
status: 'in_use',
created_at: '1970-01-01T00:00:00.000Z',
updated_at: '1970-01-01T00:00:00.000Z',
diff --git a/apps/studio/lib/api/self-hosted/signing-keys.ts b/apps/studio/lib/api/self-hosted/signing-keys.ts
index 86eb60d58f323..3541f2e8e7128 100644
--- a/apps/studio/lib/api/self-hosted/signing-keys.ts
+++ b/apps/studio/lib/api/self-hosted/signing-keys.ts
@@ -24,6 +24,7 @@ export function getLegacySigningKey(): SigningKeyResponse {
return {
id: LEGACY_KEY_ID,
algorithm: 'HS256',
+ public_jwk: '',
status: 'in_use',
created_at: LEGACY_KEY_CREATED_AT,
updated_at: LEGACY_KEY_CREATED_AT,
diff --git a/apps/studio/pages/api/platform/organizations/[slug]/billing/subscription.ts b/apps/studio/pages/api/platform/organizations/[slug]/billing/subscription.ts
index f585fc29b4e55..d7cee03359e45 100644
--- a/apps/studio/pages/api/platform/organizations/[slug]/billing/subscription.ts
+++ b/apps/studio/pages/api/platform/organizations/[slug]/billing/subscription.ts
@@ -35,7 +35,7 @@ const handleGet = async (_req: NextApiRequest, res: NextApiResponse): Member => ({
gotrue_id: 'gotrue-test',
+ avatar_url: null,
is_sso_user: false,
metadata: {},
mfa_enabled: false,
diff --git a/apps/studio/tests/components/Organization/TeamSettings/UpdateRolesPanel.network.test.tsx b/apps/studio/tests/components/Organization/TeamSettings/UpdateRolesPanel.network.test.tsx
index c8c4ca7bbabae..0ab629a98b246 100644
--- a/apps/studio/tests/components/Organization/TeamSettings/UpdateRolesPanel.network.test.tsx
+++ b/apps/studio/tests/components/Organization/TeamSettings/UpdateRolesPanel.network.test.tsx
@@ -83,6 +83,7 @@ const buildPermission = (resource: string): AccessControlPermission => ({
const MEMBER: OrganizationMember = {
gotrue_id: 'gotrue-member',
+ avatar_url: null,
is_sso_user: false,
metadata: {},
mfa_enabled: false,
diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts
index eef705e690efe..182549218cac2 100644
--- a/packages/api-types/types/api.d.ts
+++ b/packages/api-types/types/api.d.ts
@@ -521,6 +521,35 @@ export interface paths {
patch?: never
trace?: never
}
+ '/v1/projects/{ref}/analytics/endpoints/logs': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Gets all project's logs in a single log stream
+ * @description Executes an SQL or LQL query on the project's unified logs stream.
+ *
+ * Either the `iso_timestamp_start` and `iso_timestamp_end` parameters must be provided.
+ * If both are not provided, only the last 1 minute of logs will be queried.
+ * The timestamp range must be no more than 24 hours and is rounded to the nearest minute. If the range is more than 24 hours, a validation error will be thrown.
+ *
+ * Filter by the `source` column to specify specific log sources, such as edge_logs, postgres_logs, etc.
+ *
+ * Note: SQL must be written in **ClickHouse SQL dialect**.
+ *
+ */
+ get: operations['v1-get-project-logs']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
'/v1/projects/{ref}/analytics/endpoints/logs.all': {
parameters: {
query?: never
@@ -530,6 +559,7 @@ export interface paths {
}
/**
* Gets project's logs
+ * @deprecated
* @description Executes a SQL query on the project's logs.
*
* Either the `iso_timestamp_start` and `iso_timestamp_end` parameters must be provided.
@@ -539,7 +569,27 @@ export interface paths {
* Note: Unless the `sql` parameter is provided, only edge_logs will be queried. See the [log query docs](/docs/guides/telemetry/logs?queryGroups=product&product=postgres&queryGroups=source&source=edge_logs#querying-with-the-logs-explorer:~:text=logs%20from%20the-,Sources,-drop%2Ddown%3A) for all available sources.
*
*/
- get: operations['v1-get-project-logs']
+ get: operations['v1-get-project-logs-all']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v1/projects/{ref}/analytics/endpoints/metrics': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Scrape a project's metrics
+ * @description Prometheus scrape endpoint. Returns metrics of a customer project in the Prometheus open exposition format.
+ */
+ get: operations['v1-scrape-project-metrics']
put?: never
post?: never
delete?: never
@@ -1315,6 +1365,66 @@ export interface paths {
patch?: never
trace?: never
}
+ '/v1/projects/{ref}/database/jit/invite': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Invites an external user to a database for JIT access
+ * @description Invites the external user and sets initial roles that can be assumed and for how long
+ */
+ post: operations['v1-invite-external-jit-access']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v1/projects/{ref}/database/jit/invite/{invite_id}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ post?: never
+ /**
+ * Deletes the invite for an external user to a database for JIT access
+ * @description Revokes and deletes the invitation
+ */
+ delete: operations['v1-delete-invite-external-jit-access']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v1/projects/{ref}/database/jit/invite/accept': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Accepts invitation for JIT database access
+ * @description Accepts the invitation to JIT database access
+ */
+ post: operations['v1-accept-invite-external-jit-access']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
'/v1/projects/{ref}/database/jit/list': {
parameters: {
query?: never
@@ -1342,25 +1452,13 @@ export interface paths {
path?: never
cookie?: never
}
- /**
- * List applied migration versions
- * @description Only available to selected partner OAuth apps
- */
+ /** List applied migration versions */
get: operations['v1-list-migration-history']
- /**
- * Upsert a database migration without applying
- * @description Only available to selected partner OAuth apps
- */
+ /** Upsert a database migration without applying */
put: operations['v1-upsert-a-migration']
- /**
- * Apply a database migration
- * @description Only available to selected partner OAuth apps
- */
+ /** Apply a database migration */
post: operations['v1-apply-a-migration']
- /**
- * Rollback database migrations and remove them from history table
- * @description Only available to selected partner OAuth apps
- */
+ /** Rollback database migrations and remove them from history table */
delete: operations['v1-rollback-migrations']
options?: never
head?: never
@@ -1374,20 +1472,14 @@ export interface paths {
path?: never
cookie?: never
}
- /**
- * Fetch an existing entry from migration history
- * @description Only available to selected partner OAuth apps
- */
+ /** Fetch an existing entry from migration history */
get: operations['v1-get-a-migration']
put?: never
post?: never
delete?: never
options?: never
head?: never
- /**
- * Patch an existing entry in migration history
- * @description Only available to selected partner OAuth apps
- */
+ /** Patch an existing entry in migration history */
patch: operations['v1-patch-a-migration']
trace?: never
}
@@ -2114,6 +2206,15 @@ export interface paths {
export type webhooks = Record
export interface components {
schemas: {
+ /** @example {
+ * "email": "external-user@somedomain.xyz",
+ * "token": ""
+ * } */
+ AcceptInviteExternalUserJitAccessBody: {
+ /** Format: email */
+ email: string
+ token: string
+ }
ActionRunResponse: {
branch_id: string
check_run_id: number | null
@@ -2749,7 +2850,6 @@ export interface components {
domains?: {
created_at?: string
domain?: string
- id: string
updated_at?: string
}[]
id: string
@@ -2765,7 +2865,6 @@ export interface components {
}
}
entity_id: string
- id: string
metadata_url?: string
metadata_xml?: string
/** @enum {string} */
@@ -2932,7 +3031,6 @@ export interface components {
domains?: {
created_at?: string
domain?: string
- id: string
updated_at?: string
}[]
id: string
@@ -2948,7 +3046,6 @@ export interface components {
}
}
entity_id: string
- id: string
metadata_url?: string
metadata_xml?: string
/** @enum {string} */
@@ -3053,7 +3150,7 @@ export interface components {
* }
* } */
FunctionDeployBody: {
- file?: string[]
+ file: string[]
metadata: {
entrypoint_path: string
import_map_path?: string
@@ -3122,7 +3219,6 @@ export interface components {
domains?: {
created_at?: string
domain?: string
- id: string
updated_at?: string
}[]
id: string
@@ -3138,7 +3234,6 @@ export interface components {
}
}
entity_id: string
- id: string
metadata_url?: string
metadata_xml?: string
/** @enum {string} */
@@ -3150,6 +3245,63 @@ export interface components {
}
updated_at?: string
}
+ /** @example {
+ * "email": "external-user@somedomain.xyz",
+ * "roles": [
+ * {
+ * "role": "postgres",
+ * "expires_at": 1740787200,
+ * "allowed_networks": {
+ * "allowed_cidrs": [
+ * {
+ * "cidr": "203.0.113.0/24"
+ * }
+ * ]
+ * },
+ * "branches_only": false
+ * }
+ * ]
+ * } */
+ InviteExternalUserJitAccessBody: {
+ /** Format: email */
+ email: string
+ roles: {
+ allowed_networks?: {
+ allowed_cidrs?: {
+ /** Format: cidrv4 */
+ cidr: string
+ }[]
+ allowed_cidrs_v6?: {
+ /** Format: cidrv6 */
+ cidr: string
+ }[]
+ }
+ branches_only?: boolean
+ expires_at?: number
+ role: string
+ }[]
+ }
+ InviteExternalUserJitResponse: {
+ /** Format: email */
+ email: string
+ /** Format: uuid */
+ invite_id: string
+ user_roles: {
+ allowed_networks?: {
+ allowed_cidrs?: {
+ /** Format: cidrv4 */
+ cidr: string
+ }[]
+ allowed_cidrs_v6?: {
+ /** Format: cidrv6 */
+ cidr: string
+ }[]
+ }
+ branches_only?: boolean
+ expires_at?: number
+ role: string
+ }[]
+ }
/** @example {
* "state": "enabled"
* } */
@@ -3159,13 +3311,15 @@ export interface components {
}
JitAccessResponse: {
/** Format: uuid */
- user_id: string
+ user_id?: string
user_roles: {
allowed_networks?: {
allowed_cidrs?: {
+ /** Format: cidrv4 */
cidr: string
}[]
allowed_cidrs_v6?: {
+ /** Format: cidrv6 */
cidr: string
}[]
}
@@ -3180,9 +3334,11 @@ export interface components {
user_role: {
allowed_networks?: {
allowed_cidrs?: {
+ /** Format: cidrv4 */
cidr: string
}[]
allowed_cidrs_v6?: {
+ /** Format: cidrv6 */
cidr: string
}[]
}
@@ -3193,14 +3349,19 @@ export interface components {
}
JitListAccessResponse: {
items: {
+ expires_at: null
+ invite_id: null
+ primary_email: string | null
/** Format: uuid */
user_id: string
user_roles: {
allowed_networks?: {
allowed_cidrs?: {
+ /** Format: cidrv4 */
cidr: string
}[]
allowed_cidrs_v6?: {
+ /** Format: cidrv6 */
cidr: string
}[]
}
@@ -3210,22 +3371,6 @@ export interface components {
}[]
}[]
}
- JitStateResponse:
- | {
- appliedSuccessfully?: boolean
- /** @enum {string} */
- state: 'enabled' | 'disabled'
- }
- | {
- /** @enum {string} */
- state: 'unavailable'
- /** @enum {string} */
- unavailableReason:
- | 'manual_migration_required'
- | 'postgres_upgrade_required'
- | 'ssl_enforcement_required'
- | 'temporarily_unavailable'
- }
LegacyApiKeysResponse: {
enabled: boolean
}
@@ -3288,8 +3433,7 @@ export interface components {
| 'auth_mfa_web_authn_default'
| 'log_drain_default'
| 'etl_pipeline_default'
- /** @description Any JSON-serializable value */
- meta?: unknown
+ meta?: components['schemas']['ListProjectAddonsResponseJsonValue']
name: string
price: {
amount: number
@@ -3341,8 +3485,7 @@ export interface components {
| 'auth_mfa_web_authn_default'
| 'log_drain_default'
| 'etl_pipeline_default'
- /** @description Any JSON-serializable value */
- meta?: unknown
+ meta?: components['schemas']['ListProjectAddonsResponseJsonValue']
name: string
price: {
amount: number
@@ -3355,13 +3498,19 @@ export interface components {
}
}[]
}
+ /** @description Any JSON-serializable value */
+ ListProjectAddonsResponseJsonValue:
+ | ((string | number | boolean) | null)
+ | components['schemas']['ListProjectAddonsResponseJsonValue'][]
+ | {
+ [key: string]: components['schemas']['ListProjectAddonsResponseJsonValue']
+ }
ListProvidersResponse: {
items: {
created_at?: string
domains?: {
created_at?: string
domain?: string
- id: string
updated_at?: string
}[]
id: string
@@ -3377,7 +3526,6 @@ export interface components {
}
}
entity_id: string
- id: string
metadata_url?: string
metadata_xml?: string
/** @enum {string} */
@@ -3437,7 +3585,17 @@ export interface components {
NetworkRestrictionsResponse: {
/** Format: date-time */
applied_at?: string
- /** @description At any given point in time, this is the config that the user has requested be applied to their project. The `status` field indicates if it has been applied to the project, or is pending. When an updated config is received, the applied config is moved to `old_config`. */
+ /**
+ * @description At any given point in time, this is the config that the user has requested be applied to their project. The `status` field indicates if it has been applied to the project, or is pending. When an updated config is received, the applied config is moved to `old_config`.
+ * @example {
+ * "dbAllowedCidrs": [
+ * "203.0.113.0/24"
+ * ],
+ * "dbAllowedCidrsV6": [
+ * "2001:db8::/32"
+ * ]
+ * }
+ */
config: {
dbAllowedCidrs?: string[]
dbAllowedCidrsV6?: string[]
@@ -3669,9 +3827,29 @@ export interface components {
*/
slug: string
}
+ /** @example {
+ * "root_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+ * } */
PgsodiumConfigResponse: {
+ /** @description The pgsodium root key: 32 bytes, hex-encoded (64 characters). */
root_key: string
}
+ PlanGateErrorBody: {
+ /** @description Present on entitlement denials. Other errors with this status code (validation, billing state) carry only message. */
+ error?: {
+ /**
+ * @description Machine-readable marker for plan-gated denials
+ * @enum {string}
+ */
+ code: 'entitlement_required'
+ /** @description Entitlement feature key that failed the check */
+ feature: string
+ /** @description Billing page URL for the organization, present when the org is resolvable */
+ upgrade_url?: string
+ }
+ /** @description Human-readable explanation of the plan gate */
+ message: string
+ }
PostgresConfigResponse: {
/** @description Default unit: s */
checkpoint_timeout?: string
@@ -3694,6 +3872,7 @@ export interface components {
maintenance_work_mem?: string
max_connections?: number
max_locks_per_transaction?: number
+ max_logical_replication_workers?: number
max_parallel_maintenance_workers?: number
max_parallel_workers?: number
max_parallel_workers_per_gather?: number
@@ -3701,6 +3880,7 @@ export interface components {
max_slot_wal_keep_size?: string
max_standby_archive_delay?: string
max_standby_streaming_delay?: string
+ max_sync_workers_per_subscription?: number
max_wal_senders?: number
max_wal_size?: string
max_worker_processes?: number
@@ -3720,6 +3900,8 @@ export interface components {
db_extra_search_path: string
/** @description If `null`, the value is automatically configured based on compute size. */
db_pool: number | null
+ /** @description If `null`, the value is automatically configured to 10. */
+ db_pool_acquisition_timeout: number | null
db_schema: string
jwt_secret?: string
max_rows: number
@@ -3807,7 +3989,6 @@ export interface components {
}
| {
obj_name: string
- /** @enum {string} */
obj_type: 'table' | 'function'
schema_name: string
/** @enum {string} */
@@ -3906,7 +4087,7 @@ export interface components {
| 'sa-east-1'
name: string
/** @enum {string} */
- provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
/** @enum {string} */
status?: 'capacity' | 'other'
/** @enum {string} */
@@ -3944,7 +4125,7 @@ export interface components {
| 'sa-east-1'
name: string
/** @enum {string} */
- provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
/** @enum {string} */
status?: 'capacity' | 'other'
/** @enum {string} */
@@ -4014,7 +4195,7 @@ export interface components {
created_at: string
/** Format: uuid */
id: string
- public_jwk?: unknown
+ public_jwk: unknown
/** @enum {string} */
status: 'in_use' | 'previously_used' | 'revoked' | 'standby'
/** Format: date-time */
@@ -4028,7 +4209,7 @@ export interface components {
created_at: string
/** Format: uuid */
id: string
- public_jwk?: unknown
+ public_jwk: unknown
/** @enum {string} */
status: 'in_use' | 'previously_used' | 'revoked' | 'standby'
/** Format: date-time */
@@ -4131,6 +4312,9 @@ export interface components {
imageTransformation: {
enabled: boolean
}
+ purgeCache: {
+ enabled: boolean
+ }
s3Protocol: {
enabled: boolean
}
@@ -4483,8 +4667,8 @@ export interface components {
UpdateCustomHostnameResponse: {
custom_hostname: string
data: {
- errors: unknown[]
- messages: unknown[]
+ errors: components['schemas']['UpdateCustomHostnameResponseJsonValue'][]
+ messages: components['schemas']['UpdateCustomHostnameResponseJsonValue'][]
result: {
custom_origin_server: string
hostname: string
@@ -4517,6 +4701,13 @@ export interface components {
| '4_origin_setup_completed'
| '5_services_reconfigured'
}
+ /** @description Any JSON-serializable value */
+ UpdateCustomHostnameResponseJsonValue:
+ | ((string | number | boolean) | null)
+ | components['schemas']['UpdateCustomHostnameResponseJsonValue'][]
+ | {
+ [key: string]: components['schemas']['UpdateCustomHostnameResponseJsonValue']
+ }
/** @example {
* "user_id": "55555555-5555-4555-8555-555555555555",
* "roles": [
@@ -4538,9 +4729,11 @@ export interface components {
roles: {
allowed_networks?: {
allowed_cidrs?: {
+ /** Format: cidrv4 */
cidr: string
}[]
allowed_cidrs_v6?: {
+ /** Format: cidrv6 */
cidr: string
}[]
}
@@ -4552,9 +4745,10 @@ export interface components {
user_id: string
}
/** @example {
- * "root_key": "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY="
+ * "root_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
* } */
UpdatePgsodiumConfigBody: {
+ /** @description The pgsodium root key: 32 bytes, hex-encoded (64 characters). */
root_key: string
}
/** @example {
@@ -4585,6 +4779,7 @@ export interface components {
maintenance_work_mem?: string
max_connections?: number
max_locks_per_transaction?: number
+ max_logical_replication_workers?: number
max_parallel_maintenance_workers?: number
max_parallel_workers?: number
max_parallel_workers_per_gather?: number
@@ -4592,6 +4787,7 @@ export interface components {
max_slot_wal_keep_size?: string
max_standby_archive_delay?: string
max_standby_streaming_delay?: string
+ max_sync_workers_per_subscription?: number
max_wal_senders?: number
max_wal_size?: string
max_worker_processes?: number
@@ -4641,7 +4837,6 @@ export interface components {
domains?: {
created_at?: string
domain?: string
- id: string
updated_at?: string
}[]
id: string
@@ -4657,7 +4852,6 @@ export interface components {
}
}
entity_id: string
- id: string
metadata_url?: string
metadata_xml?: string
/** @enum {string} */
@@ -4754,6 +4948,9 @@ export interface components {
imageTransformation?: {
enabled: boolean
}
+ purgeCache?: {
+ enabled: boolean
+ }
s3Protocol?: {
enabled: boolean
}
@@ -4875,6 +5072,8 @@ export interface components {
| '48xlarge_optimized_memory'
| '48xlarge_optimized_cpu'
| '48xlarge_high_memory'
+ /** @description [Experimental] Whether to enable high availability for the project. */
+ high_availability?: boolean
/**
* @deprecated
* @description This field is deprecated and is ignored in this request
@@ -4898,6 +5097,8 @@ export interface components {
* @enum {string}
*/
plan?: 'free' | 'pro'
+ /** @deprecated */
+ postgres_engine?: null
/**
* @deprecated
* @description Region you want your server to reside in. Use region_selection instead.
@@ -4960,6 +5161,8 @@ export interface components {
/** @enum {string} */
type: 'smartGroup'
}
+ /** @deprecated */
+ release_channel?: null
/**
* Format: uri
* @description Template URL used to create the project from the CLI.
@@ -5047,6 +5250,7 @@ export interface components {
| 'storage.image_transformations'
| 'storage.vector_buckets'
| 'storage.iceberg_catalog'
+ | 'storage.purge_cache'
| 'security.audit_logs_days'
| 'security.questionnaire'
| 'security.soc2_report'
@@ -5096,6 +5300,8 @@ export interface components {
| 'integrations.github_connections'
| 'dedicated_pooler'
| 'observability.dashboard_advanced_metrics'
+ | 'api.members.invitations'
+ | 'api.members.roles'
/** @enum {string} */
type: 'boolean' | 'numeric' | 'set'
}
@@ -5109,6 +5315,7 @@ export interface components {
version: string
}[]
V1OrganizationMemberResponse: {
+ avatar_url: string | null
email?: string
mfa_enabled: boolean
role_name: string
@@ -5151,6 +5358,8 @@ export interface components {
db_extra_search_path: string
/** @description If `null`, the value is automatically configured based on compute size. */
db_pool: number | null
+ /** @description If `null`, the value is automatically configured to 10. */
+ db_pool_acquisition_timeout: number | null
db_schema: string
max_rows: number
}
@@ -5451,6 +5660,7 @@ export interface components {
V1UpdatePostgrestConfigBody: {
db_extra_search_path?: string
db_pool?: number
+ db_pool_acquisition_timeout?: number
db_schema?: string
max_rows?: number
}
@@ -5523,7 +5733,7 @@ export interface operations {
parameters: {
query?: {
/** @description If set to false, schedule deletion with 1-hour grace period (only when soft deletion is enabled). */
- force?: boolean
+ force?: string
}
header?: never
path: {
@@ -5588,8 +5798,13 @@ export interface operations {
parameters: {
query?: {
included_schemas?: string
- /** @description Use pg-delta instead of Migra for diffing when true */
- pgdelta?: boolean
+ /** @description Use pg-delta instead of Migra for diffing when true.
+ * Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ pgdelta?: string
}
header?: never
path: {
@@ -5760,6 +5975,7 @@ export interface operations {
response_type: 'code' | 'token' | 'id_token token'
scope?: string
state?: string
+ target_flow?: string
}
header?: never
path?: never
@@ -6908,6 +7124,68 @@ export interface operations {
}
content?: never
}
+ /** @description Usage exceeded. Enable additional usage to continue querying */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ 'v1-get-project-logs-all': {
+ parameters: {
+ query?: {
+ iso_timestamp_end?: string
+ iso_timestamp_start?: string
+ /** @description Custom SQL query to execute on the logs. See [querying logs](/docs/guides/telemetry/logs?queryGroups=product&product=postgres&queryGroups=source&source=edge_logs#querying-with-the-logs-explorer) for more details. */
+ sql?: string
+ }
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['AnalyticsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Usage exceeded. Enable additional usage to continue querying */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -6924,6 +7202,58 @@ export interface operations {
}
}
}
+ 'v1-scrape-project-metrics': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Prometheus / OpenMetrics text exposition */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/openmetrics-text': string
+ 'text/plain': string
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to fetch project's metrics */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
'v1-get-project-usage-api-count': {
parameters: {
query?: {
@@ -7029,8 +7359,12 @@ export interface operations {
'v1-get-project-api-keys': {
parameters: {
query?: {
- /** @description Boolean string, true or false */
- reveal?: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ reveal?: string
}
header?: never
path: {
@@ -7075,8 +7409,12 @@ export interface operations {
'v1-create-project-api-key': {
parameters: {
query?: {
- /** @description Boolean string, true or false */
- reveal?: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ reveal?: string
}
header?: never
path: {
@@ -7125,8 +7463,12 @@ export interface operations {
'v1-get-project-api-key': {
parameters: {
query?: {
- /** @description Boolean string, true or false */
- reveal?: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ reveal?: string
}
header?: never
path: {
@@ -7174,9 +7516,9 @@ export interface operations {
query?: {
reason?: string
/** @description Boolean string, true or false */
- reveal?: boolean
+ reveal?: string
/** @description Boolean string, true or false */
- was_compromised?: boolean
+ was_compromised?: string
}
header?: never
path: {
@@ -7222,8 +7564,12 @@ export interface operations {
'v1-update-project-api-key': {
parameters: {
query?: {
- /** @description Boolean string, true or false */
- reveal?: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ reveal?: string
}
header?: never
path: {
@@ -7316,8 +7662,12 @@ export interface operations {
'v1-update-project-legacy-api-keys': {
parameters: {
query: {
- /** @description Boolean string, true or false */
- enabled: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ enabled: string
}
header?: never
path: {
@@ -9513,7 +9863,7 @@ export interface operations {
parameters: {
query?: {
/** @description If true, also removes the custom domain add-on from the project subscription. */
- remove_addon?: boolean
+ remove_addon?: string
}
header?: never
path: {
@@ -9985,7 +10335,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -10060,7 +10412,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -10275,7 +10629,7 @@ export interface operations {
}
content?: never
}
- /** @description Failed to upsert database migration */
+ /** @description Failed to update JIT access */
500: {
headers: {
[name: string]: unknown
@@ -10387,6 +10741,142 @@ export interface operations {
}
}
}
+ 'v1-invite-external-jit-access': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['InviteExternalUserJitAccessBody']
+ }
+ }
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['InviteExternalUserJitResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to invite external user */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ 'v1-delete-invite-external-jit-access': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ invite_id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to revoke invite for external user */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ 'v1-accept-invite-external-jit-access': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['AcceptInviteExternalUserJitAccessBody']
+ }
+ }
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['JitAccessResponse']
+ }
+ }
+ /** @description Failed to accept invitation */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
'v1-list-jit-access': {
parameters: {
query?: never
@@ -11127,13 +11617,11 @@ export interface operations {
query?: {
entrypoint_path?: string
ezbr_sha256?: string
- /** @description Boolean string, true or false */
- import_map?: boolean
+ import_map?: string
import_map_path?: string
name?: string
slug?: string
- /** @description Boolean string, true or false */
- verify_jwt?: boolean
+ verify_jwt?: string
}
header?: never
path: {
@@ -11301,13 +11789,11 @@ export interface operations {
query?: {
entrypoint_path?: string
ezbr_sha256?: string
- /** @description Boolean string, true or false */
- import_map?: boolean
+ import_map?: string
import_map_path?: string
name?: string
slug?: string
- /** @description Boolean string, true or false */
- verify_jwt?: boolean
+ verify_jwt?: string
}
header?: never
path: {
@@ -11418,8 +11904,7 @@ export interface operations {
'v1-deploy-a-function': {
parameters: {
query?: {
- /** @description Boolean string, true or false */
- bundleOnly?: boolean
+ bundleOnly?: string
slug?: string
}
header?: never
@@ -11483,16 +11968,19 @@ export interface operations {
'v1-get-services-health': {
parameters: {
query: {
- services: (
- | 'auth'
- | 'db'
- | 'db_postgres_user'
- | 'pooler'
- | 'realtime'
- | 'rest'
- | 'storage'
- | 'pg_bouncer'
- )[]
+ /** @description Comma-separated list of enums or array of enums. */
+ services:
+ | string
+ | (
+ | 'auth'
+ | 'db'
+ | 'db_postgres_user'
+ | 'pooler'
+ | 'realtime'
+ | 'rest'
+ | 'storage'
+ | 'pg_bouncer'
+ )[]
timeout_ms?: number
}
header?: never
@@ -11559,7 +12047,21 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['JitStateResponse']
+ 'application/json':
+ | {
+ appliedSuccessfully?: boolean
+ /** @enum {string} */
+ state: 'enabled' | 'disabled'
+ }
+ | {
+ /** @constant */
+ state: 'unavailable'
+ /** @enum {string} */
+ unavailableReason:
+ | 'postgres_upgrade_required'
+ | 'ssl_enforcement_required'
+ | 'temporarily_unavailable'
+ }
}
}
/** @description Unauthorized */
@@ -11613,7 +12115,21 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['JitStateResponse']
+ 'application/json':
+ | {
+ appliedSuccessfully?: boolean
+ /** @enum {string} */
+ state: 'enabled' | 'disabled'
+ }
+ | {
+ /** @constant */
+ state: 'unavailable'
+ /** @enum {string} */
+ unavailableReason:
+ | 'postgres_upgrade_required'
+ | 'ssl_enforcement_required'
+ | 'temporarily_unavailable'
+ }
}
}
/** @description Unauthorized */
@@ -12291,7 +12807,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -13121,7 +13639,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Unauthorized */
401: {
@@ -13230,7 +13750,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Unauthorized */
401: {
@@ -13291,7 +13813,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Unauthorized */
401: {
diff --git a/packages/api-types/types/platform.d.ts b/packages/api-types/types/platform.d.ts
index 622b9dd1b784a..7e85290092779 100644
--- a/packages/api-types/types/platform.d.ts
+++ b/packages/api-types/types/platform.d.ts
@@ -520,23 +520,6 @@ export interface paths {
patch?: never
trace?: never
}
- '/platform/feedback/docs': {
- parameters: {
- query?: never
- header?: never
- path?: never
- cookie?: never
- }
- get?: never
- put?: never
- /** Send feedback on docs */
- post: operations['SendFeedbackController_sendDocsFeedback']
- delete?: never
- options?: never
- head?: never
- patch?: never
- trace?: never
- }
'/platform/feedback/downgrade': {
parameters: {
query?: never
@@ -683,6 +666,26 @@ export interface paths {
patch: operations['GitHubConnectionsController_updateGitHubConnection']
trace?: never
}
+ '/platform/integrations/github/connections/{connection_id}/config': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Gets the Supabase config of a connected GitHub repository
+ * @description Reads `supabase/config.toml` from the workdir of the connected repository and returns it as JSON.
+ */
+ get: operations['GitHubConnectionsController_getGitHubConnectionConfig']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
'/platform/integrations/github/repositories': {
parameters: {
query?: never
@@ -1984,11 +1987,9 @@ export interface paths {
}
/** Gets the given organization's tax ID */
get: operations['TaxIdsController_getTaxId']
- /** Creates or updates a tax ID for the given organization */
- put: operations['TaxIdsController_updateTaxId']
+ put?: never
post?: never
- /** Delete the tax ID with the given ID */
- delete: operations['TaxIdsController_deleteTaxId']
+ delete?: never
options?: never
head?: never
patch?: never
@@ -2592,6 +2593,24 @@ export interface paths {
patch?: never
trace?: never
}
+ '/platform/projects/{ref}/analytics/endpoints/logs': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /** Gets project's logs from the unified logs stream */
+ get: operations['LogsController_getProjectLogsViaGetNew']
+ put?: never
+ /** Gets project's logs from the unified logs stream */
+ post: operations['LogsController_getProjectLogsViaPostNew']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
'/platform/projects/{ref}/analytics/endpoints/logs.all': {
parameters: {
query?: never
@@ -2599,10 +2618,16 @@ export interface paths {
path?: never
cookie?: never
}
- /** Gets project's logs */
+ /**
+ * Gets project's logs from legacy logs tables
+ * @deprecated
+ */
get: operations['LogsController_getProjectLogsViaGet']
put?: never
- /** Gets project's logs */
+ /**
+ * Gets project's logs from legacy logs tables
+ * @deprecated
+ */
post: operations['LogsController_getProjectLogsViaPost']
delete?: never
options?: never
@@ -2617,10 +2642,16 @@ export interface paths {
path?: never
cookie?: never
}
- /** Gets project's logs from the ClickHouse-backed endpoint */
+ /**
+ * Gets project's logs from the unified logs stream
+ * @deprecated
+ */
get: operations['LogsController_getProjectLogsOtelViaGet']
put?: never
- /** Gets project's logs from the ClickHouse-backed endpoint */
+ /**
+ * Gets project's logs from the unified logs stream
+ * @deprecated
+ */
post: operations['LogsController_getProjectLogsOtelViaPost']
delete?: never
options?: never
@@ -2767,6 +2798,26 @@ export interface paths {
patch?: never
trace?: never
}
+ '/platform/projects/{ref}/analytics/metrics': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Scrape a project's metrics
+ * @description Prometheus scrape endpoint. Returns metrics of a customer project in the Prometheus open exposition format. Replaces `/customer/v1/privileged/metrics`.
+ */
+ get: operations['scrape-project-metrics']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
'/platform/projects/{ref}/api-keys/temporary': {
parameters: {
query?: never
@@ -3394,7 +3445,7 @@ export interface paths {
post?: never
/**
* Remove AWS account from PrivateLink share for the project
- * @description Removes an AWS account from the project's PrivateLink configuration. Cleans up associated AWS resources.
+ * @description Removes an AWS account from the project's PrivateLink configuration (targeting the primary database). Cleans up associated AWS resources.
*/
delete: operations['ProjectPrivateLinkController_removeAwsAccountFromPrivateLink']
options?: never
@@ -3402,6 +3453,26 @@ export interface paths {
patch?: never
trace?: never
}
+ '/platform/projects/{ref}/privatelink/associations/aws-account/{aws_account_id}/database/{database_identifier}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ post?: never
+ /**
+ * Remove AWS account from a specific database PrivateLink share for the project
+ * @description Removes an AWS account from the project's PrivateLink configuration for the given read replica. Cleans up associated AWS resources.
+ */
+ delete: operations['ProjectPrivateLinkController_removeAwsAccountFromPrivateLinkForDatabase']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
'/platform/projects/{ref}/resize': {
parameters: {
query?: never
@@ -3504,57 +3575,6 @@ export interface paths {
patch?: never
trace?: never
}
- '/platform/projects/{ref}/run-lints/{name}': {
- parameters: {
- query?: never
- header?: never
- path?: never
- cookie?: never
- }
- /** Run project lint by name */
- get: operations['ProjectRunLintsController_runLintByName']
- put?: never
- post?: never
- delete?: never
- options?: never
- head?: never
- patch?: never
- trace?: never
- }
- '/platform/projects/{ref}/run-lints/leaked-service-key': {
- parameters: {
- query?: never
- header?: never
- path?: never
- cookie?: never
- }
- /** Run project leaked service key lint */
- get: operations['ProjectRunLintsController_runLeakedServiceKeyLint']
- put?: never
- post?: never
- delete?: never
- options?: never
- head?: never
- patch?: never
- trace?: never
- }
- '/platform/projects/{ref}/run-lints/no-backup-admin': {
- parameters: {
- query?: never
- header?: never
- path?: never
- cookie?: never
- }
- /** Run project backup admin lint */
- get: operations['ProjectRunLintsController_runAuthBackupAdminLint']
- put?: never
- post?: never
- delete?: never
- options?: never
- head?: never
- patch?: never
- trace?: never
- }
'/platform/projects/{ref}/service-versions': {
parameters: {
query?: never
@@ -4104,7 +4124,7 @@ export interface paths {
}
/**
* Estimate replication cost for a publication
- * @description Estimate the cost of replicating a publication's tables. Returns the flat per-pipeline fee, a per-table breakdown of the one-time initial-copy cost derived from the tables’ on-disk size, and the usage-based streaming rate. Requires bearer auth and an active, healthy project.
+ * @description Estimate the cost of replicating a publication's tables. Returns the hourly (and projected monthly) per-pipeline fee, a per-table breakdown of the one-time initial-copy cost derived from the tables’ on-disk size, and the usage-based streaming rate. Requires bearer auth and an active, healthy project.
*/
get: operations['ReplicationSourcesController_getCostEstimate']
put?: never
@@ -4539,6 +4559,40 @@ export interface paths {
patch?: never
trace?: never
}
+ '/platform/storage/{ref}/cdn/purge-bucket': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /** Purges CDN cache for an entire bucket */
+ post: operations['StorageCdnController_purgeBucketCache']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/platform/storage/{ref}/cdn/purge-object': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /** Purges CDN cache for a single object */
+ post: operations['StorageCdnController_purgeObjectCache']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
'/platform/storage/{ref}/credentials': {
parameters: {
query?: never
@@ -4903,90 +4957,220 @@ export interface paths {
patch?: never
trace?: never
}
- '/platform/workflow-runs': {
+ '/platform/warehouse/{ref}/catalog': {
parameters: {
query?: never
header?: never
path?: never
cookie?: never
}
- /** Get a list of workflow runs */
- get: operations['WorkflowRunController_listWorkflowRuns']
+ /**
+ * Get Warehouse catalog access
+ * @description Return whether external Warehouse catalog access is enabled and credentials when enabled.
+ */
+ get: operations['WarehouseController_getCatalog']
put?: never
- post?: never
+ /**
+ * Update Warehouse catalog access
+ * @description Enable or disable external Warehouse catalog access for the project.
+ */
+ post: operations['WarehouseController_updateCatalog']
delete?: never
options?: never
head?: never
patch?: never
trace?: never
}
- '/platform/workflow-runs/{workflow_run_id}/logs': {
+ '/platform/warehouse/{ref}/refresh-schema': {
parameters: {
query?: never
header?: never
path?: never
cookie?: never
}
- /** Get the logs of a workflow run */
- get: operations['WorkflowRunController_getWorkflowRunLogs']
+ get?: never
put?: never
- post?: never
+ /**
+ * Refresh the Warehouse foreign schema
+ * @description Reinstall the project Warehouse FDW schema asynchronously without restarting replication or waiting for a table copy.
+ */
+ post: operations['WarehouseController_refreshSchema']
delete?: never
options?: never
head?: never
patch?: never
trace?: never
}
-}
-export type webhooks = Record
-export interface components {
- schemas: {
- AccessControlPermission: {
- actions: string[] | null
- condition:
- | (
- | string
- | number
- | boolean
- | unknown[]
- | {
- [key: string]: unknown
- }
- )
- | null
- organization_id: number | null
- organization_slug: string
- project_ids: number[] | null
- project_refs: string[] | null
- resources: string[] | null
- restrictive: boolean | null
+ '/platform/warehouse/{ref}/setup-status': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
}
- AccessToken: {
- created_at: string
- expires_at: string | null
- id: number
- last_used_at: string | null
- name: string
- /** @enum {string} */
- scope?: 'V0'
- token_alias: string
+ /**
+ * Get Warehouse setup status
+ * @description Return the async Warehouse setup status for the project. Overall completion follows the replication pipeline and table copy state; project database FDW markers are informational.
+ */
+ get: operations['WarehouseController_getSetupStatus']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/platform/warehouse/{ref}/tables': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
}
- AccountRequestDetailsDto: {
- email: string
- email_matches: boolean
- expires_at: string
- id: string
- linked_organization?: {
- id: number
- name: string
- slug: string
- }
- /** @enum {string} */
- status: 'pending' | 'complete' | 'expired' | 'error'
+ /**
+ * List Warehouse linked tables
+ * @description List tables copied to Warehouse for the project. Requires bearer auth and an active, healthy project.
+ */
+ get: operations['WarehouseController_getTables']
+ put?: never
+ /**
+ * Copy a table to Warehouse
+ * @description Ensure the project Warehouse pipeline exists, add the table to its publication, and start syncing. Warehouse FDW installation is opt-in.
+ */
+ post: operations['WarehouseController_linkTable']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/platform/warehouse/{ref}/tables/{schema}/{name}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
}
- AddAwsAccountToPrivateLinkBody: {
- account_name?: string
+ get?: never
+ put?: never
+ post?: never
+ /**
+ * Detach a table from Warehouse
+ * @description Remove the table from the Warehouse publication so it stops syncing. Existing DuckLake data is left in place.
+ */
+ delete: operations['WarehouseController_detachTable']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/platform/warehouse/{ref}/tables/{schema}/{name}/snapshots': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List Warehouse snapshots for a table
+ * @description Return available DuckLake snapshots for a Warehouse-linked table. The snapshots are read from the Warehouse FDW in the project database.
+ */
+ get: operations['WarehouseController_getTableSnapshots']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/platform/workflow-runs': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /** Get a list of workflow runs */
+ get: operations['WorkflowRunController_listWorkflowRuns']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/platform/workflow-runs/{workflow_run_id}/logs': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /** Get the logs of a workflow run */
+ get: operations['WorkflowRunController_getWorkflowRunLogs']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+}
+export type webhooks = Record
+export interface components {
+ schemas: {
+ AccessControlPermission: {
+ actions: string[] | null
+ condition:
+ | (
+ | string
+ | number
+ | boolean
+ | unknown[]
+ | {
+ [key: string]: unknown
+ }
+ )
+ | null
+ organization_id: number | null
+ organization_slug: string
+ project_ids: number[] | null
+ project_refs: string[] | null
+ resources: string[] | null
+ restrictive: boolean | null
+ }
+ AccessToken: {
+ created_at: string
+ expires_at: string | null
+ id: number
+ last_used_at: string | null
+ name: string
+ /** @enum {string} */
+ scope?: 'V0'
+ token_alias: string
+ }
+ AccountRequestDetailsDto: {
+ email: string
+ email_matches: boolean
+ expires_at: string
+ id: string
+ linked_organization?: {
+ id: number
+ name: string
+ slug: string
+ }
+ /** @enum {string} */
+ status: 'pending' | 'complete' | 'expired' | 'error'
+ }
+ AddAwsAccountToPrivateLinkBody: {
+ account_name?: string
aws_account_id: string
+ /** @description Identifier of the read replica this PrivateLink share should target. Omit to target the primary database. */
+ database_identifier?: string
}
AnalyticsResponse: {
error?:
@@ -5020,6 +5204,9 @@ export interface components {
}
method: string
name: string
+ params?: {
+ [key: string]: unknown
+ }
route: string
status: number
}
@@ -5027,10 +5214,24 @@ export interface components {
app_id?: string
app_name?: string
email?: string
+ /** @description Only present when token_type=app */
+ installation_id?: string
ip?: string
+ /** @description JWT issuer. Only present for branching service JWTs */
+ jwt_issuer?: string
+ /** @description JWT subject. Only present for branching service JWTs */
+ jwt_subject?: string
oauth_app_id?: string
oauth_app_name?: string
+ /** @description Organization whose grant was used. Only present when token_type=oauth */
+ organization_id?: string
+ /** @description GoTrue login session. Only present when token_type=jwt */
+ session_id?: string
+ /** @description Access token alias, as shown in the dashboard. Only present when token_type=v0, token_type=v1 or token_type=scoped_pat */
+ token_alias?: string
token_hash?: string
+ /** @description Only present when token_type=scoped_pat */
+ token_scope?: string
token_type: string
user_id?: string
}
@@ -5041,60 +5242,6 @@ export interface components {
}[]
retention_period: number
}
- AuthBackupAdminLintResponse: {
- lints: {
- cache_key: string
- categories: ('PERFORMANCE' | 'SECURITY')[]
- description: string
- detail: string
- /** @enum {string} */
- facing: 'EXTERNAL'
- /** @enum {string} */
- level: 'ERROR' | 'WARN' | 'INFO'
- metadata?: {
- entity?: string
- fkey_columns?: number[]
- fkey_name?: string
- name?: string
- schema?: string
- /** @enum {string} */
- type?: 'table' | 'view' | 'auth' | 'function' | 'extension' | 'compliance'
- }
- /** @enum {string} */
- name:
- | 'unindexed_foreign_keys'
- | 'auth_users_exposed'
- | 'auth_rls_initplan'
- | 'no_primary_key'
- | 'unused_index'
- | 'multiple_permissive_policies'
- | 'policy_exists_rls_disabled'
- | 'rls_enabled_no_policy'
- | 'duplicate_index'
- | 'security_definer_view'
- | 'function_search_path_mutable'
- | 'rls_disabled_in_public'
- | 'extension_in_public'
- | 'rls_references_user_metadata'
- | 'materialized_view_in_api'
- | 'foreign_table_in_api'
- | 'unsupported_reg_types'
- | 'auth_otp_long_expiry'
- | 'auth_otp_short_length'
- | 'ssl_not_enforced'
- | 'network_restrictions_not_set'
- | 'password_requirements_min_length'
- | 'pitr_not_enabled'
- | 'auth_leaked_password_protection'
- | 'auth_insufficient_mfa_options'
- | 'auth_password_policy_missing'
- | 'leaked_service_key'
- | 'no_backup_admin'
- | 'vulnerable_postgres_version'
- remediation: string
- title: string
- }[]
- }
BackendConnectionTest: {
'connected?': boolean
reason: string
@@ -5131,7 +5278,7 @@ export interface components {
clear_tax_id?: true
dry_run?: boolean
tax_id?: {
- country?: string
+ country: string
type: string
value: string
}
@@ -5220,6 +5367,81 @@ export interface components {
CopyObjectResponse: {
path: string
}
+ CostEstimateResponse: {
+ /**
+ * @description Currency of all amounts
+ * @example usd
+ * @enum {string}
+ */
+ currency: 'usd'
+ /** @description Recurring per-pipeline cost */
+ pipeline: {
+ /**
+ * @description Hourly rate charged per active pipeline
+ * @example 0.053
+ */
+ hourly_cost: number
+ /**
+ * @description Projected monthly cost for an active pipeline, based on an average 730-hour month. Pipelines are billed hourly, so this is an estimate, not a metered amount.
+ * @example 38.69
+ */
+ monthly_cost: number
+ }
+ /** @description Usage-based streaming cost, expressed as a rate */
+ streaming: {
+ /**
+ * @description Usage-based streaming rate per GB. Actual cost depends on the change volume.
+ * @example 3
+ */
+ rate_per_gb: number
+ }
+ /** @description One-time cost for the initial table copy */
+ table_copy: {
+ /**
+ * @description One-time initial-copy rate per GB
+ * @example 0.6
+ */
+ rate_per_gb: number
+ /** @description Per-table initial-copy cost estimate */
+ tables: {
+ /**
+ * @description Estimated on-disk size of the table in bytes
+ * @example 10960896
+ */
+ estimated_bytes: number
+ /**
+ * @description Estimated one-time initial-copy cost for the table, in the response currency
+ * @example 0.01
+ */
+ estimated_cost: number
+ /**
+ * @description Whether this table has a row filter. The estimate does not account for how many rows the filter excludes, so the actual replicated volume may be lower than shown.
+ * @example false
+ */
+ is_row_filtered: boolean
+ /**
+ * @description Table name
+ * @example orders
+ */
+ name: string
+ /**
+ * @description Table schema
+ * @example public
+ */
+ schema: string
+ }[]
+ /**
+ * @description Total estimated bytes across all tables
+ * @example 11911168
+ */
+ total_bytes: number
+ /**
+ * @description Total estimated one-time initial-copy cost
+ * @example 0.01
+ */
+ total_cost: number
+ }
+ }
CreateAccessTokenBody: {
/** Format: date-time */
expires_at?: string
@@ -5389,12 +5611,7 @@ export interface components {
workdir: string
}
CreateInvitationBody: {
- /**
- * Format: email
- * @deprecated
- */
- email?: string
- emails?: string[]
+ emails: string[]
require_sso?: boolean
role_id: number
role_scoped_projects?: string[]
@@ -5566,7 +5783,7 @@ export interface components {
payment_method?: string
size?: string
tax_id?: {
- country?: string
+ country: string
type: string
value: string
}
@@ -5579,37 +5796,6 @@ export interface components {
| 'tier_enterprise'
| 'tier_platform'
}
- CreateOrganizationResponse:
- | {
- pending_payment_intent_secret: string | null
- }
- | {
- billing_email: string | null
- /** @enum {string|null} */
- billing_partner: 'fly' | 'aws_marketplace' | 'vercel_marketplace' | null
- id: number
- integration_source: string | null
- is_owner: boolean
- name: string
- opt_in_tags: string[]
- organization_missing_address: boolean
- organization_missing_tax_id: boolean
- organization_requires_mfa: boolean
- plan: {
- /** @enum {string} */
- id: 'free' | 'pro' | 'team' | 'enterprise' | 'platform'
- name: string
- }
- restriction_data: {
- [key: string]: string
- } | null
- /** @enum {string|null} */
- restriction_status: 'grace_period' | 'grace_period_over' | 'restricted' | null
- slug: string
- stripe_customer_id: string | null
- subscription_id: string | null
- usage_billing_enabled: boolean
- }
CreatePipelineResponse: {
/**
* @description Pipeline id
@@ -5631,6 +5817,8 @@ export interface components {
| 'members_write'
| 'organization_projects_read'
| 'organization_projects_create'
+ | 'platform_webhooks_organization_read'
+ | 'platform_webhooks_organization_write'
| 'project_admin_read'
| 'project_admin_write'
| 'action_runs_read'
@@ -5700,6 +5888,8 @@ export interface components {
| 'storage_config_write'
| 'vanity_subdomain_read'
| 'vanity_subdomain_write'
+ | 'platform_webhooks_projects_read'
+ | 'platform_webhooks_projects_write'
)[]
}
CreatePlatformAppResponse: {
@@ -5728,9 +5918,9 @@ export interface components {
CreateProjectBody: {
auth_site_url?: string
/** @enum {string} */
- cloud_provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ cloud_provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
custom_supabase_internal_requests?: {
- ami: {
+ ami?: {
/**
* @description Exact AWS instance type to provision (e.g. `t3.nano`, `t4g.nano`). Hard pin — no ODCR fallback. Only for internal use; rejected for user-facing requests in production.
* @enum {string}
@@ -5740,16 +5930,67 @@ export interface components {
| 't3a.nano'
| 't3.nano'
| 't4g.micro'
+ | 't3a.micro'
+ | 't3.micro'
| 't4g.small'
+ | 't3a.small'
+ | 't3.small'
| 't4g.medium'
+ | 't3a.medium'
+ | 't3.medium'
| 'm6g.medium'
+ | 'm7g.medium'
+ | 'm8g.medium'
+ | 'm9g.medium'
| 'm6g.large'
+ | 'm6a.large'
+ | 'm6i.large'
+ | 'm7i.large'
+ | 'm8i.large'
+ | 'm7a.large'
+ | 'm8a.large'
| 'm6g.xlarge'
+ | 'm6a.xlarge'
+ | 'm6i.xlarge'
+ | 'm7i.xlarge'
+ | 'm8i.xlarge'
+ | 'm7a.xlarge'
+ | 'm8a.xlarge'
| 'm6g.2xlarge'
+ | 'm6a.2xlarge'
+ | 'm6i.2xlarge'
+ | 'm7i.2xlarge'
+ | 'm8i.2xlarge'
+ | 'm7a.2xlarge'
+ | 'm8a.2xlarge'
| 'm6g.4xlarge'
+ | 'm6a.4xlarge'
+ | 'm6i.4xlarge'
+ | 'm7i.4xlarge'
+ | 'm8i.4xlarge'
+ | 'm7a.4xlarge'
+ | 'm8a.4xlarge'
| 'm6g.8xlarge'
+ | 'm6a.8xlarge'
+ | 'm6i.8xlarge'
+ | 'm7i.8xlarge'
+ | 'm8i.8xlarge'
+ | 'm7a.8xlarge'
+ | 'm8a.8xlarge'
| 'm6g.12xlarge'
+ | 'm6a.12xlarge'
+ | 'm6i.12xlarge'
+ | 'm7i.12xlarge'
+ | 'm8i.12xlarge'
+ | 'm7a.12xlarge'
+ | 'm8a.12xlarge'
| 'm6g.16xlarge'
+ | 'm6a.16xlarge'
+ | 'm6i.16xlarge'
+ | 'm7i.16xlarge'
+ | 'm8i.16xlarge'
+ | 'm7a.16xlarge'
+ | 'm8a.16xlarge'
| 'm8g.24xlarge'
| 'c8g.24xlarge'
| 'r8g.24xlarge'
@@ -5767,6 +6008,26 @@ export interface components {
[key: string]: string
}
}
+ warehouse_fdw?: {
+ /** @description AWS ACM Private CA ARN used by the worker to issue per-project warehouse FDW client certificates. Defaults to the worker environment configuration when omitted. */
+ client_certificate_authority_arn?: string
+ /** @description Optional URI SAN to place in the issued client certificate. Defaults to spiffe://supabase//postgres//. */
+ client_certificate_identity_uri?: string
+ client_certificate_ttl_days?: number
+ connect_timeout_ms?: number
+ enabled?: boolean
+ endpoint: string
+ jwt_audience?: string
+ jwt_issuer?: string
+ jwt_kid: string
+ jwt_ttl_secs?: number
+ request_timeout_ms?: number
+ /** @description Optional legacy input. The platform derives the runtime AWS Secrets Manager prefix from the project ref as warehouse-fdw/. */
+ secret_prefix?: string
+ secret_region?: string
+ stream_idle_timeout_ms?: number
+ tls_domain_name?: string
+ }
}
data_api_exposed_schemas?: string[]
data_api_revoke_default_privileges?: boolean
@@ -5815,7 +6076,29 @@ export interface components {
/** @description Provider region selection. Only one of db_region or region_selection can be specified. */
region_selection?:
| {
- code: string
+ /**
+ * @description The selected region code must be valid for the specified cloud provider.
+ * @enum {string}
+ */
+ code:
+ | 'us-east-1'
+ | 'us-east-2'
+ | 'us-west-1'
+ | 'us-west-2'
+ | 'ap-east-1'
+ | 'ap-southeast-1'
+ | 'ap-northeast-1'
+ | 'ap-northeast-2'
+ | 'ap-southeast-2'
+ | 'eu-west-1'
+ | 'eu-west-2'
+ | 'eu-west-3'
+ | 'eu-north-1'
+ | 'eu-central-1'
+ | 'eu-central-2'
+ | 'ca-central-1'
+ | 'ap-south-1'
+ | 'sa-east-1'
/** @enum {string} */
type: 'specific'
}
@@ -6167,7 +6450,7 @@ export interface components {
private_key_passphrase?: string | null
/**
* @description Optional Snowflake role
- * @example ETL_ROLE
+ * @example PIPELINES_ROLE
*/
role?: string | null
/**
@@ -6177,7 +6460,7 @@ export interface components {
schema: string
/**
* @description Snowflake user configured for key-pair authentication
- * @example ETL_USER
+ * @example PIPELINES_USER
*/
user: string
}
@@ -6479,7 +6762,7 @@ export interface components {
private_key_passphrase?: string | null
/**
* @description Optional Snowflake role
- * @example ETL_ROLE
+ * @example PIPELINES_ROLE
*/
role?: string | null
/**
@@ -6489,7 +6772,7 @@ export interface components {
schema: string
/**
* @description Snowflake user configured for key-pair authentication
- * @example ETL_USER
+ * @example PIPELINES_USER
*/
user: string
}
@@ -6530,7 +6813,7 @@ export interface components {
* @example info
* @enum {string|null}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn' | null
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | null
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number | null
/** @description Maximum number of table sync workers */
@@ -6605,7 +6888,7 @@ export interface components {
/** @enum {string} */
type: 'skip_tables'
}
- | (never | null)
+ | never
}
/**
* @description Source id
@@ -6645,7 +6928,7 @@ export interface components {
* @example info
* @enum {string|null}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn' | null
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | null
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number | null
/** @description Maximum number of table sync workers */
@@ -6720,7 +7003,7 @@ export interface components {
/** @enum {string} */
type: 'skip_tables'
}
- | (never | null)
+ | never
}
/**
* @description Destination id
@@ -6769,6 +7052,8 @@ export interface components {
| 'members_write'
| 'organization_projects_read'
| 'organization_projects_create'
+ | 'platform_webhooks_organization_read'
+ | 'platform_webhooks_organization_write'
| 'project_admin_read'
| 'project_admin_write'
| 'action_runs_read'
@@ -6838,6 +7123,8 @@ export interface components {
| 'storage_config_write'
| 'vanity_subdomain_read'
| 'vanity_subdomain_write'
+ | 'platform_webhooks_projects_read'
+ | 'platform_webhooks_projects_write'
)[]
project_refs?: string[]
}
@@ -6891,46 +7178,13 @@ export interface components {
metadata_xml_url: string
user_name_mapping?: string[]
}
- CreateSSOProviderResponse:
- | {
- /** @default [] */
- domains?: string[]
- email_mapping: string[]
- enabled: boolean
- first_name_mapping?: string[]
- /** Format: uri */
- idjag_issuer_url?: string | null
- join_org_on_signup_enabled: boolean
- /** @enum {string} */
- join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
- last_name_mapping?: string[]
- metadata_xml_file: string
- /** Format: uri */
- metadata_xml_url?: string
- user_name_mapping?: string[]
- }
- | {
- /** @default [] */
- domains?: string[]
- email_mapping: string[]
- enabled: boolean
- first_name_mapping?: string[]
- /** Format: uri */
- idjag_issuer_url?: string | null
- join_org_on_signup_enabled: boolean
- /** @enum {string} */
- join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
- last_name_mapping?: string[]
- metadata_xml_file?: string
- metadata_xml_url: string
- user_name_mapping?: string[]
- }
CreateStorageAnalyticsBucketBody: {
bucketName: string
}
CreateStorageBucketBody: {
allowed_mime_types?: string[]
file_size_limit?: number
+ /** @description Storage bucket id */
id: string
public: boolean
/** @enum {string} */
@@ -6948,11 +7202,6 @@ export interface components {
CreateStorageVectorBucketBody: {
bucketName: string
}
- CreateTaxIdBody: {
- country?: string
- type: string
- value: string
- }
CreateTenantSourceResponse: {
/**
* @description Source id
@@ -6977,7 +7226,7 @@ export interface components {
parent_id?: string | null
project_id: number
}
- CreateUserReponse: {
+ CreateUserResponse: {
aud?: string
banned_until?: string
confirmation_sent_at?: string
@@ -7055,7 +7304,6 @@ export interface components {
}
CreditRedemptionResponse: {
amount_cents: number
- /** Format: date-time */
credits_expire_at: string | null
}
CreditsTopUpRequest: {
@@ -7112,7 +7360,7 @@ export interface components {
}
DatabaseDetailResponse: {
/** @enum {string} */
- cloud_provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ cloud_provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
/** @default null */
connection_string_read_only?: string | null
/** @default null */
@@ -7325,7 +7573,6 @@ export interface components {
logo_uri?: string
redirect_uris: string[]
response_types?: string[]
- /** @default organizations:read projects:read projects:write database:write database:read analytics:read secrets:read edge_functions:read edge_functions:write environment:read environment:write storage:read */
scope?: string
token_endpoint_auth_method?: string
}
@@ -7346,71 +7593,26 @@ export interface components {
private: number
shared: number
}
- GetJwtSecretUpdateStatus: {
- update_status: {
- change_tracking_id: string
- /** @enum {number} */
- error?: 0 | 1 | 2 | 3 | 4 | 5
- /** @enum {number} */
+ GetGitHubConnectionConfigResponse: {
+ /** @description JSON representation of the parsed `supabase/config.toml`. Its shape is owned by the Supabase CLI and is passed through as-is. */
+ config: {
+ [key: string]: unknown
+ }
+ /** @description Path of the config file within the connected repository, relative to its root. */
+ path: string
+ /** @description Git ref the config was read from, or `null` when the default branch of the connected repository was used. */
+ ref: string | null
+ /** @description Blob SHA of the config file, to detect changes between requests. */
+ sha: string
+ }
+ GetJwtSecretUpdateStatus: {
+ update_status: {
+ change_tracking_id: string
+ error?: 0 | 1 | 2 | 3 | 4 | 5
progress: 0 | 1 | 2 | 3 | 4 | 5
- /** @enum {number} */
status: 0 | 1 | 2
} | null
}
- GetLeakedServiceKeyLintResponse: {
- lints: {
- cache_key: string
- categories: ('PERFORMANCE' | 'SECURITY')[]
- description: string
- detail: string
- /** @enum {string} */
- facing: 'EXTERNAL'
- /** @enum {string} */
- level: 'ERROR' | 'WARN' | 'INFO'
- metadata?: {
- entity?: string
- fkey_columns?: number[]
- fkey_name?: string
- name?: string
- schema?: string
- /** @enum {string} */
- type?: 'table' | 'view' | 'auth' | 'function' | 'extension' | 'compliance'
- }
- /** @enum {string} */
- name:
- | 'unindexed_foreign_keys'
- | 'auth_users_exposed'
- | 'auth_rls_initplan'
- | 'no_primary_key'
- | 'unused_index'
- | 'multiple_permissive_policies'
- | 'policy_exists_rls_disabled'
- | 'rls_enabled_no_policy'
- | 'duplicate_index'
- | 'security_definer_view'
- | 'function_search_path_mutable'
- | 'rls_disabled_in_public'
- | 'extension_in_public'
- | 'rls_references_user_metadata'
- | 'materialized_view_in_api'
- | 'foreign_table_in_api'
- | 'unsupported_reg_types'
- | 'auth_otp_long_expiry'
- | 'auth_otp_short_length'
- | 'ssl_not_enforced'
- | 'network_restrictions_not_set'
- | 'password_requirements_min_length'
- | 'pitr_not_enabled'
- | 'auth_leaked_password_protection'
- | 'auth_insufficient_mfa_options'
- | 'auth_password_policy_missing'
- | 'leaked_service_key'
- | 'no_backup_admin'
- | 'vulnerable_postgres_version'
- remediation: string
- title: string
- }[]
- }
GetOAuthAuthorizationResponse: {
approved_at?: string
approved_organization_slug?: string
@@ -7495,13 +7697,19 @@ export interface components {
integration: {
name: string
}
- /** @description Any JSON-serializable value */
- metadata: unknown
+ metadata: components['schemas']['GetOrganizationIntegrationResponseJsonValue']
organization: {
slug: string
}
updated_at: string
}
+ /** @description Any JSON-serializable value */
+ GetOrganizationIntegrationResponseJsonValue:
+ | ((string | number | boolean) | null)
+ | components['schemas']['GetOrganizationIntegrationResponseJsonValue'][]
+ | {
+ [key: string]: components['schemas']['GetOrganizationIntegrationResponseJsonValue']
+ }
GetPlatformAppInstallationResponse: {
/** Format: uuid */
app_id: string
@@ -7541,6 +7749,13 @@ export interface components {
private_link_associations: {
account_name?: string
aws_account_id: string
+ /** @description Identifier of the database this PrivateLink share targets - the project ref for the primary, or the read replica identifier. */
+ database_identifier: string
+ /**
+ * @description Whether this PrivateLink share targets the primary database or a read replica.
+ * @enum {string}
+ */
+ database_type: 'PRIMARY' | 'READ_REPLICA'
/**
* Format: date-time
* @description The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.
@@ -7750,40 +7965,6 @@ export interface components {
}
path: string[]
}
- GetSSOProviderResponse:
- | {
- /** @default [] */
- domains?: string[]
- email_mapping: string[]
- enabled: boolean
- first_name_mapping?: string[]
- /** Format: uri */
- idjag_issuer_url?: string | null
- join_org_on_signup_enabled: boolean
- /** @enum {string} */
- join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
- last_name_mapping?: string[]
- metadata_xml_file: string
- /** Format: uri */
- metadata_xml_url?: string
- user_name_mapping?: string[]
- }
- | {
- /** @default [] */
- domains?: string[]
- email_mapping: string[]
- enabled: boolean
- first_name_mapping?: string[]
- /** Format: uri */
- idjag_issuer_url?: string | null
- join_org_on_signup_enabled: boolean
- /** @enum {string} */
- join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
- last_name_mapping?: string[]
- metadata_xml_file?: string
- metadata_xml_url: string
- user_name_mapping?: string[]
- }
GetStorageCredentialsResponse: {
data: {
created_at: string
@@ -7799,7 +7980,7 @@ export interface components {
}[]
billing_cycle_anchor: number
/** @enum {string} */
- billing_partner?: 'fly' | 'aws_marketplace' | 'vercel_marketplace'
+ billing_partner?: 'aws_marketplace' | 'vercel_marketplace'
billing_via_partner: boolean
current_period_end: number
current_period_start: number
@@ -7854,8 +8035,7 @@ export interface components {
| 'auth_mfa_web_authn_default'
| 'log_drain_default'
| 'etl_pipeline_default'
- /** @description Any JSON-serializable value */
- meta?: unknown
+ meta?: components['schemas']['GetSubscriptionResponseJsonValue']
name: string
price: number
price_description: string
@@ -7869,7 +8049,6 @@ export interface components {
ref: string
}[]
scheduled_plan_change: {
- /** Format: date-time */
at: string
/** @enum {string} */
target_plan: 'free' | 'pro' | 'team' | 'enterprise' | 'platform'
@@ -7877,6 +8056,13 @@ export interface components {
} | null
usage_billing_enabled: boolean
}
+ /** @description Any JSON-serializable value */
+ GetSubscriptionResponseJsonValue:
+ | ((string | number | boolean) | null)
+ | components['schemas']['GetSubscriptionResponseJsonValue'][]
+ | {
+ [key: string]: components['schemas']['GetSubscriptionResponseJsonValue']
+ }
GetUserContentByIdResponse: {
content: {
[key: string]: unknown
@@ -7964,13 +8150,19 @@ export interface components {
integration: {
name: string
}
- /** @description Any JSON-serializable value */
- metadata: unknown
+ metadata: components['schemas']['GetUserOrganizationIntegrationResponseJsonValue']
organization: {
slug: string
}
updated_at: string
}
+ /** @description Any JSON-serializable value */
+ GetUserOrganizationIntegrationResponseJsonValue:
+ | ((string | number | boolean) | null)
+ | components['schemas']['GetUserOrganizationIntegrationResponseJsonValue'][]
+ | {
+ [key: string]: components['schemas']['GetUserOrganizationIntegrationResponseJsonValue']
+ }
GetVercelProjectsResponse: {
pagination: {
count: number
@@ -8380,14 +8572,14 @@ export interface components {
tls?: boolean
}
description?: string
- id: number
- metadata: {
+ readonly id: number
+ readonly metadata: {
project_ref: string
/** @enum {string} */
type: 'log-drain'
} | null
name: string
- token: string
+ readonly token: string
/** @enum {string} */
type:
| 'postgres'
@@ -8402,7 +8594,7 @@ export interface components {
| 'last9'
| 'otlp'
| 'syslog'
- user_id: number
+ readonly user_id: number
}
LinkClazarBuyerBody: {
buyer_id: string
@@ -8437,6 +8629,7 @@ export interface components {
| 'storage.image_transformations'
| 'storage.vector_buckets'
| 'storage.iceberg_catalog'
+ | 'storage.purge_cache'
| 'security.audit_logs_days'
| 'security.questionnaire'
| 'security.soc2_report'
@@ -8486,6 +8679,8 @@ export interface components {
| 'integrations.github_connections'
| 'dedicated_pooler'
| 'observability.dashboard_advanced_metrics'
+ | 'api.members.invitations'
+ | 'api.members.roles'
/** @enum {string} */
type: 'boolean' | 'numeric' | 'set'
}
@@ -8678,6 +8873,7 @@ export interface components {
is_sensitive: boolean
}
Member: {
+ avatar_url: string | null
gotrue_id: string
is_sso_user: boolean | null
metadata: {
@@ -8736,18 +8932,23 @@ export interface components {
'table-uuid'?: string
}
NotificationResponse: {
- /** @description Any JSON-serializable value */
- data: unknown
+ data: components['schemas']['NotificationResponseJsonValue']
id: string
inserted_at: string
- /** @description Any JSON-serializable value */
- meta: unknown
+ meta: components['schemas']['NotificationResponseJsonValue']
name: string
/** @enum {string} */
priority: 'Critical' | 'Warning' | 'Info'
/** @enum {string} */
status: 'new' | 'seen' | 'archived'
}
+ /** @description Any JSON-serializable value */
+ NotificationResponseJsonValue:
+ | ((string | number | boolean) | null)
+ | components['schemas']['NotificationResponseJsonValue'][]
+ | {
+ [key: string]: components['schemas']['NotificationResponseJsonValue']
+ }
NotificationsSummary: {
has_critical: boolean
has_warning: boolean
@@ -8887,7 +9088,7 @@ export interface components {
OrganizationResponse: {
billing_email: string | null
/** @enum {string|null} */
- billing_partner: 'fly' | 'aws_marketplace' | 'vercel_marketplace' | null
+ billing_partner: 'aws_marketplace' | 'vercel_marketplace' | null
id: number
integration_source: string | null
is_owner: boolean
@@ -8943,7 +9144,7 @@ export interface components {
}
OrganizationSlugAvailableVersionsBody: {
/** @enum {string} */
- provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
region: string
}
OrganizationSlugAvailableVersionsResponse: {
@@ -8958,7 +9159,7 @@ export interface components {
OrganizationSlugResponse: {
billing_email: string | null
/** @enum {string|null} */
- billing_partner: 'fly' | 'aws_marketplace' | 'vercel_marketplace' | null
+ billing_partner: 'aws_marketplace' | 'vercel_marketplace' | null
has_oriole_project: boolean
id: number
integration_source: string | null
@@ -8988,6 +9189,7 @@ export interface components {
egress_storage: number
egress_supavisor: number
} | null
+ /** Format: date */
date: string
/** @enum {string} */
metric:
@@ -9037,6 +9239,8 @@ export interface components {
| 'IPV4'
| 'LOG_DRAIN'
| 'ETL_PIPELINE'
+ | 'ETL_REPLICATED_DATA'
+ | 'ETL_COPY_BACKFILL_DATA'
| 'LOG_INGESTION'
| 'LOG_QUERYING'
| 'LOG_STORAGE'
@@ -9102,6 +9306,8 @@ export interface components {
| 'IPV4'
| 'LOG_DRAIN'
| 'ETL_PIPELINE'
+ | 'ETL_REPLICATED_DATA'
+ | 'ETL_COPY_BACKFILL_DATA'
| 'LOG_INGESTION'
| 'LOG_QUERYING'
| 'LOG_STORAGE'
@@ -9241,6 +9447,22 @@ export interface components {
}
}
}
+ PlanGateErrorBody: {
+ /** @description Present on entitlement denials. Other errors with this status code (validation, billing state) carry only message. */
+ error?: {
+ /**
+ * @description Machine-readable marker for plan-gated denials
+ * @enum {string}
+ */
+ code: 'entitlement_required'
+ /** @description Entitlement feature key that failed the check */
+ feature: string
+ /** @description Billing page URL for the organization, present when the org is resolvable */
+ upgrade_url?: string
+ }
+ /** @description Human-readable explanation of the plan gate */
+ message: string
+ }
PlansResponse: {
plans: {
/** @enum {string} */
@@ -9507,7 +9729,7 @@ export interface components {
state?: string | null
}
tax_id?: {
- country?: string
+ country: string
type: string
value: string
}
@@ -9682,23 +9904,7 @@ export interface components {
}
ProfileResponse: {
auth0_id: string
- disabled_features: (
- | 'organizations:create'
- | 'organizations:delete'
- | 'organization_members:create'
- | 'organization_members:delete'
- | 'projects:create'
- | 'projects:transfer'
- | 'project_auth:all'
- | 'project_storage:all'
- | 'project_edge_function:all'
- | 'profile:update'
- | 'billing:account_data'
- | 'billing:credits'
- | 'billing:invoices'
- | 'billing:payment_methods'
- | 'realtime:all'
- )[]
+ disabled_features: string[]
first_name: string | null
free_project_limit: number | null
gotrue_id: string
@@ -9753,8 +9959,7 @@ export interface components {
| 'auth_mfa_web_authn_default'
| 'log_drain_default'
| 'etl_pipeline_default'
- /** @description Any JSON-serializable value */
- meta?: unknown
+ meta?: components['schemas']['ProjectAddonsResponseJsonValue']
name: string
price: number
price_description: string
@@ -9806,8 +10011,7 @@ export interface components {
| 'auth_mfa_web_authn_default'
| 'log_drain_default'
| 'etl_pipeline_default'
- /** @description Any JSON-serializable value */
- meta?: unknown
+ meta?: components['schemas']['ProjectAddonsResponseJsonValue']
name: string
price: number
price_description: string
@@ -9818,6 +10022,13 @@ export interface components {
}
}[]
}
+ /** @description Any JSON-serializable value */
+ ProjectAddonsResponseJsonValue:
+ | ((string | number | boolean) | null)
+ | components['schemas']['ProjectAddonsResponseJsonValue'][]
+ | {
+ [key: string]: components['schemas']['ProjectAddonsResponseJsonValue']
+ }
ProjectClonedResponse: {
source_project_ref: string
target_disk_size_gb: number
@@ -9992,6 +10203,15 @@ export interface components {
PublicUrlResponse: {
publicUrl: string
}
+ PurgeBucketCacheBody: {
+ /** @description Storage bucket id */
+ bucket_id: string
+ }
+ PurgeObjectCacheBody: {
+ /** @description Storage bucket id */
+ bucket_id: string
+ path: string
+ }
PutOAuthAppResponse: {
client_id: string
created_at: string
@@ -10057,7 +10277,7 @@ export interface components {
| 'sa-east-1'
name: string
/** @enum {string} */
- provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
/** @enum {string} */
status?: 'capacity' | 'other'
/** @enum {string} */
@@ -10095,7 +10315,7 @@ export interface components {
| 'sa-east-1'
name: string
/** @enum {string} */
- provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
/** @enum {string} */
status?: 'capacity' | 'other'
/** @enum {string} */
@@ -10267,7 +10487,7 @@ export interface components {
database: string
/**
* @description Optional Snowflake role
- * @example ETL_ROLE
+ * @example PIPELINES_ROLE
*/
role?: string
/**
@@ -10277,7 +10497,7 @@ export interface components {
schema: string
/**
* @description Snowflake user configured for key-pair authentication
- * @example ETL_USER
+ * @example PIPELINES_USER
*/
user: string
}
@@ -10456,7 +10676,7 @@ export interface components {
database: string
/**
* @description Optional Snowflake role
- * @example ETL_ROLE
+ * @example PIPELINES_ROLE
*/
role?: string
/**
@@ -10466,7 +10686,7 @@ export interface components {
schema: string
/**
* @description Snowflake user configured for key-pair authentication
- * @example ETL_USER
+ * @example PIPELINES_USER
*/
user: string
}
@@ -10526,7 +10746,7 @@ export interface components {
* @example reserved
* @enum {string}
*/
- wal_status?: 'extended' | 'lost' | 'reserved' | 'unknown' | 'unreserved'
+ wal_status?: 'reserved' | 'extended' | 'unreserved' | 'lost' | 'unknown'
/**
* @description Write lag expressed in milliseconds.
* @example 1500
@@ -10646,7 +10866,7 @@ export interface components {
* @example reserved
* @enum {string}
*/
- wal_status?: 'extended' | 'lost' | 'reserved' | 'unknown' | 'unreserved'
+ wal_status?: 'reserved' | 'extended' | 'unreserved' | 'lost' | 'unknown'
/**
* @description Write lag expressed in milliseconds.
* @example 1500
@@ -10688,7 +10908,7 @@ export interface components {
* @example info
* @enum {string}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn'
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error'
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number
/** @description Maximum number of table sync workers */
@@ -10834,7 +11054,7 @@ export interface components {
* @example info
* @enum {string}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn'
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error'
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number
/** @description Maximum number of table sync workers */
@@ -10995,81 +11215,6 @@ export interface components {
name: string
}
}
- CostEstimateResponse: {
- /**
- * @description Currency of all amounts
- * @example usd
- * @enum {string}
- */
- currency: 'usd'
- /** @description Recurring per-pipeline cost */
- pipeline: {
- /**
- * @description Hourly rate charged per active pipeline
- * @example 0.053
- */
- hourly_cost: number
- /**
- * @description Projected monthly cost for an active pipeline, based on an average 730-hour month. Pipelines are billed hourly, so this is an estimate, not a metered amount.
- * @example 38.69
- */
- monthly_cost: number
- }
- /** @description Usage-based streaming cost, expressed as a rate */
- streaming: {
- /**
- * @description Usage-based streaming rate per GB. Actual cost depends on the change volume.
- * @example 3
- */
- rate_per_gb: number
- }
- /** @description One-time cost for the initial table copy */
- table_copy: {
- /**
- * @description One-time initial-copy rate per GB
- * @example 0.6
- */
- rate_per_gb: number
- /** @description Per-table initial-copy cost estimate */
- tables: {
- /**
- * @description Estimated on-disk size of the table in bytes
- * @example 10960896
- */
- estimated_bytes: number
- /**
- * @description Estimated one-time initial-copy cost for the table, in the response currency
- * @example 0.01
- */
- estimated_cost: number
- /**
- * @description Whether this table has a row filter. The estimate does not account for how many rows the filter excludes, so the actual replicated volume may be lower than shown.
- * @example false
- */
- is_row_filtered: boolean
- /**
- * @description Table name
- * @example orders
- */
- name: string
- /**
- * @description Table schema
- * @example public
- */
- schema: string
- }[]
- /**
- * @description Total estimated bytes across all tables
- * @example 11911168
- */
- total_bytes: number
- /**
- * @description Total estimated one-time initial-copy cost
- * @example 0.01
- */
- total_cost: number
- }
- }
ReplicationPublicationsResponse: {
/** @description List of publications */
publications: {
@@ -11308,73 +11453,12 @@ export interface components {
table_id: number
}[]
}
- RunLintByNameResponse: {
- lints: {
- cache_key: string
- categories: ('PERFORMANCE' | 'SECURITY')[]
- description: string
- detail: string
- /** @enum {string} */
- facing: 'EXTERNAL'
- /** @enum {string} */
- level: 'ERROR' | 'WARN' | 'INFO'
- metadata?: {
- entity?: string
- fkey_columns?: number[]
- fkey_name?: string
- name?: string
- schema?: string
- /** @enum {string} */
- type?: 'table' | 'view' | 'auth' | 'function' | 'extension' | 'compliance'
- }
- /** @enum {string} */
- name:
- | 'unindexed_foreign_keys'
- | 'auth_users_exposed'
- | 'auth_rls_initplan'
- | 'no_primary_key'
- | 'unused_index'
- | 'multiple_permissive_policies'
- | 'policy_exists_rls_disabled'
- | 'rls_enabled_no_policy'
- | 'duplicate_index'
- | 'security_definer_view'
- | 'function_search_path_mutable'
- | 'rls_disabled_in_public'
- | 'extension_in_public'
- | 'rls_references_user_metadata'
- | 'materialized_view_in_api'
- | 'foreign_table_in_api'
- | 'unsupported_reg_types'
- | 'auth_otp_long_expiry'
- | 'auth_otp_short_length'
- | 'ssl_not_enforced'
- | 'network_restrictions_not_set'
- | 'password_requirements_min_length'
- | 'pitr_not_enabled'
- | 'auth_leaked_password_protection'
- | 'auth_insufficient_mfa_options'
- | 'auth_password_policy_missing'
- | 'leaked_service_key'
- | 'no_backup_admin'
- | 'vulnerable_postgres_version'
- remediation: string
- title: string
- }[]
- }
RunQueryBody: {
/** @default false */
disable_statement_timeout?: boolean
parameters?: unknown[]
query: string
}
- SendDocsFeedbackBody: {
- feedback?: string
- isHelpful: boolean
- page: string
- team?: string
- title: string
- }
SendExitSurveyBody: {
additionalFeedback?: string
exitAction?: string
@@ -11494,6 +11578,9 @@ export interface components {
imageTransformation: {
enabled: boolean
}
+ purgeCache: {
+ enabled: boolean
+ }
s3Protocol: {
enabled: boolean
}
@@ -11654,7 +11741,7 @@ export interface components {
}
TelemetryFeatureFlagBody: {
feature_flag_name: string
- feature_flag_value?: unknown
+ feature_flag_value: unknown
}
TelemetryGroupsIdentityBody: {
organization_slug?: string
@@ -11710,9 +11797,7 @@ export interface components {
UpcomingInvoice: {
amount_projected?: number
amount_total: number
- /** Format: date-time */
billing_cycle_end: string
- /** Format: date-time */
billing_cycle_start: string
currency: string
customer_balance: number
@@ -11773,9 +11858,7 @@ export interface components {
is_read_replica?: boolean
}
period?: {
- /** Format: date-time */
end: string
- /** Format: date-time */
start: string
}
proration: boolean
@@ -11831,6 +11914,8 @@ export interface components {
| 'IPV4'
| 'LOG_DRAIN'
| 'ETL_PIPELINE'
+ | 'ETL_REPLICATED_DATA'
+ | 'ETL_COPY_BACKFILL_DATA'
| 'LOG_INGESTION'
| 'LOG_QUERYING'
| 'LOG_STORAGE'
@@ -12367,6 +12452,8 @@ export interface components {
| 'members_write'
| 'organization_projects_read'
| 'organization_projects_create'
+ | 'platform_webhooks_organization_read'
+ | 'platform_webhooks_organization_write'
| 'project_admin_read'
| 'project_admin_write'
| 'action_runs_read'
@@ -12436,6 +12523,8 @@ export interface components {
| 'storage_config_write'
| 'vanity_subdomain_read'
| 'vanity_subdomain_write'
+ | 'platform_webhooks_projects_read'
+ | 'platform_webhooks_projects_write'
)[]
}
UpdatePlatformAppInstallationResponse: {
@@ -12471,6 +12560,7 @@ export interface components {
UpdatePostgrestConfigBody: {
db_extra_search_path?: string
db_pool?: number
+ db_pool_acquisition_timeout?: number
db_schema?: string
max_rows?: number
}
@@ -12478,6 +12568,8 @@ export interface components {
db_extra_search_path: string
/** @description If `null`, the value is automatically configured based on compute size. */
db_pool: number | null
+ /** @description If `null`, the value is automatically configured to 10. */
+ db_pool_acquisition_timeout: number | null
db_schema: string
max_rows: number
}
@@ -12807,7 +12899,7 @@ export interface components {
private_key_passphrase?: string | null
/**
* @description Optional Snowflake role
- * @example ETL_ROLE
+ * @example PIPELINES_ROLE
*/
role?: string | null
/**
@@ -12817,7 +12909,7 @@ export interface components {
schema?: string | null
/**
* @description Snowflake user configured for key-pair authentication
- * @example ETL_USER
+ * @example PIPELINES_USER
*/
user?: string | null
}
@@ -13115,7 +13207,7 @@ export interface components {
private_key_passphrase?: string | null
/**
* @description Optional Snowflake role
- * @example ETL_ROLE
+ * @example PIPELINES_ROLE
*/
role?: string | null
/**
@@ -13125,7 +13217,7 @@ export interface components {
schema?: string | null
/**
* @description Snowflake user configured for key-pair authentication
- * @example ETL_USER
+ * @example PIPELINES_USER
*/
user?: string | null
}
@@ -13166,7 +13258,7 @@ export interface components {
* @example info
* @enum {string|null}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn' | null
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | null
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number | null
/** @description Maximum number of table sync workers */
@@ -13190,7 +13282,7 @@ export interface components {
*/
memory_refresh_interval_ms?: number | null
/**
- * @description Publication name. Omission preserves the stored value; ETL rejects clearing it with `null`.
+ * @description Publication name. Omission preserves the stored value; Pipelines rejects clearing it with `null`.
* @example pub_orders
*/
publication_name?: string | null
@@ -13241,7 +13333,7 @@ export interface components {
/** @enum {string} */
type: 'skip_tables'
}
- | (never | null)
+ | never
}
/**
* @description Source id
@@ -13281,7 +13373,7 @@ export interface components {
* @example info
* @enum {string|null}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn' | null
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | null
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number | null
/** @description Maximum number of table sync workers */
@@ -13305,7 +13397,7 @@ export interface components {
*/
memory_refresh_interval_ms?: number | null
/**
- * @description Publication name. Omission preserves the stored value; ETL rejects clearing it with `null`.
+ * @description Publication name. Omission preserves the stored value; Pipelines rejects clearing it with `null`.
* @example pub_orders
*/
publication_name?: string | null
@@ -13356,7 +13448,7 @@ export interface components {
/** @enum {string} */
type: 'skip_tables'
}
- | (never | null)
+ | never
}
/**
* @description Destination id
@@ -13432,40 +13524,6 @@ export interface components {
metadata_xml_url: string
user_name_mapping?: string[]
}
- UpdateSSOProviderResponse:
- | {
- /** @default [] */
- domains?: string[]
- email_mapping: string[]
- enabled: boolean
- first_name_mapping?: string[]
- /** Format: uri */
- idjag_issuer_url?: string | null
- join_org_on_signup_enabled: boolean
- /** @enum {string} */
- join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
- last_name_mapping?: string[]
- metadata_xml_file: string
- /** Format: uri */
- metadata_xml_url?: string
- user_name_mapping?: string[]
- }
- | {
- /** @default [] */
- domains?: string[]
- email_mapping: string[]
- enabled: boolean
- first_name_mapping?: string[]
- /** Format: uri */
- idjag_issuer_url?: string | null
- join_org_on_signup_enabled: boolean
- /** @enum {string} */
- join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
- last_name_mapping?: string[]
- metadata_xml_file?: string
- metadata_xml_url: string
- user_name_mapping?: string[]
- }
UpdateStorageBucketBody: {
allowed_mime_types?: string[] | null
file_size_limit?: number | null
@@ -13494,6 +13552,9 @@ export interface components {
imageTransformation?: {
enabled: boolean
}
+ purgeCache?: {
+ enabled: boolean
+ }
s3Protocol?: {
enabled: boolean
}
@@ -13537,7 +13598,7 @@ export interface components {
UpdateUserBody: {
ban_duration?: string
}
- UpdateUserReponse: {
+ UpdateUserResponse: {
aud?: string
banned_until?: string
confirmation_sent_at?: string
@@ -13584,6 +13645,10 @@ export interface components {
env_sync_targets?: ('production' | 'preview' | 'development')[]
public_env_var_prefix?: string
}
+ UpdateWarehouseCatalogBody: {
+ /** @description Whether external catalog access should be enabled */
+ enabled: boolean
+ }
UpsertContentBody: {
content?: {
[key: string]: unknown
@@ -13594,7 +13659,6 @@ export interface components {
* @default false
*/
favorite?: boolean
- /** Format: uuid */
folder_id?: (null | (string | null)) | null
id?: string
name: string
@@ -13613,6 +13677,9 @@ export interface components {
}
method: string
name: string
+ params?: {
+ [key: string]: unknown
+ }
route: string
status: number
}
@@ -13620,10 +13687,24 @@ export interface components {
app_id?: string
app_name?: string
email?: string
+ /** @description Only present when token_type=app */
+ installation_id?: string
ip?: string
+ /** @description JWT issuer. Only present for branching service JWTs */
+ jwt_issuer?: string
+ /** @description JWT subject. Only present for branching service JWTs */
+ jwt_subject?: string
oauth_app_id?: string
oauth_app_name?: string
+ /** @description Organization whose grant was used. Only present when token_type=oauth */
+ organization_id?: string
+ /** @description GoTrue login session. Only present when token_type=jwt */
+ session_id?: string
+ /** @description Access token alias, as shown in the dashboard. Only present when token_type=v0, token_type=v1 or token_type=scoped_pat */
+ token_alias?: string
token_hash?: string
+ /** @description Only present when token_type=scoped_pat */
+ token_scope?: string
token_type: string
user_id?: string
}
@@ -14010,7 +14091,7 @@ export interface components {
private_key_passphrase?: string | null
/**
* @description Optional Snowflake role
- * @example ETL_ROLE
+ * @example PIPELINES_ROLE
*/
role?: string | null
/**
@@ -14020,7 +14101,7 @@ export interface components {
schema: string
/**
* @description Snowflake user configured for key-pair authentication
- * @example ETL_USER
+ * @example PIPELINES_USER
*/
user: string
}
@@ -14056,7 +14137,7 @@ export interface components {
* @example info
* @enum {string|null}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn' | null
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | null
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number | null
/** @description Maximum number of table sync workers */
@@ -14131,7 +14212,7 @@ export interface components {
/** @enum {string} */
type: 'skip_tables'
}
- | (never | null)
+ | never
}
/**
* @description Source id
@@ -14171,7 +14252,7 @@ export interface components {
* @example info
* @enum {string|null}
*/
- log_level?: 'debug' | 'error' | 'info' | 'trace' | 'warn' | null
+ log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | null
/** @description Maximum number of copy connections per table */
max_copy_connections_per_table?: number | null
/** @description Maximum number of table sync workers */
@@ -14246,7 +14327,7 @@ export interface components {
/** @enum {string} */
type: 'skip_tables'
}
- | (never | null)
+ | never
}
/**
* @description Source id
@@ -14275,45 +14356,316 @@ export interface components {
/** @enum {string} */
result: 'success'
}
- WorkflowRunResponse: {
- branch_id: string
- check_run_id: number | null
- created_at: string
- git_config?: unknown
- id: string
- /** @enum {string} */
- status:
- | 'CREATING_PROJECT'
- | 'RUNNING_MIGRATIONS'
- | 'MIGRATIONS_PASSED'
- | 'MIGRATIONS_FAILED'
- | 'FUNCTIONS_DEPLOYED'
- | 'FUNCTIONS_FAILED'
- updated_at: string
- workdir: string | null
- }
- }
- responses: never
- parameters: never
- requestBodies: never
- headers: never
- pathItems: never
-}
-export type $defs = Record
-export interface operations {
- GoTrueConfigController_getGoTrueConfig: {
- parameters: {
- query?: never
- header?: never
- path: {
- /** @description Project ref */
- ref: string
+ WarehouseCatalogResponse: {
+ /** @description External catalog credentials. Present only when enabled. */
+ credentials?: {
+ /**
+ * @description DuckLake catalog Postgres URL
+ * @example postgres://postgres:@db.example.supabase.co:5432/postgres
+ */
+ catalog_url: string
+ /**
+ * @description DuckLake object storage path
+ * @example s3://warehouse/
+ */
+ data_path: string
+ /**
+ * @description DuckLake metadata schema in the catalog database
+ * @example ducklake
+ */
+ metadata_schema: string
+ /** @description S3 access key id */
+ s3_access_key_id: string
+ /**
+ * @description S3-compatible storage endpoint without protocol
+ * @example abcjuqabhgwjjutfvtpa.storage.supabase.co/storage/v1/s3
+ */
+ s3_endpoint: string
+ /**
+ * @description S3-compatible storage region
+ * @example us-east-1
+ */
+ s3_region: string
+ /** @description S3 secret access key */
+ s3_secret_access_key: string
}
- cookie?: never
+ /** @description Whether external catalog access is enabled */
+ enabled: boolean
}
- requestBody?: never
- responses: {
- 200: {
+ WarehouseLinkedTable: {
+ /**
+ * @description Warehouse-facing table name
+ * @example warehouse.orders
+ */
+ copy_name: string
+ /**
+ * @description Replication lag in milliseconds, when available
+ * @example 12000
+ */
+ lag_ms?: number
+ /**
+ * Format: date-time
+ * @description Last sync timestamp, when available
+ * @example 2026-06-23T17:48:00Z
+ */
+ last_synced_at?: string
+ /**
+ * @description Postgres table name
+ * @example orders
+ */
+ name: string
+ /**
+ * @description Postgres schema name
+ * @example public
+ */
+ schema: string
+ /**
+ * @description Warehouse copy sync state derived from replication status
+ * @example live
+ * @enum {string}
+ */
+ state: 'syncing' | 'live' | 'error'
+ /**
+ * @description Warehouse table size in bytes, when available
+ * @example 197912092672
+ */
+ warehouse_size_bytes?: number
+ }
+ WarehouseLinkTableBody: {
+ /**
+ * @description Whether to configure and install the Warehouse FDW in the project database. Defaults to false.
+ * @example false
+ */
+ install_fdw?: boolean
+ /**
+ * @description Postgres table name
+ * @example orders
+ */
+ name: string
+ /**
+ * @description Postgres schema name
+ * @example public
+ */
+ schema: string
+ }
+ WarehouseSetupStatusResponse: {
+ /** @description Project database FDW setup markers used to derive the Warehouse FDW phase */
+ fdw_status: {
+ /**
+ * @description Whether fdw_warehouse is available to install on the project database instance
+ * @example true
+ */
+ extension_available: boolean
+ /**
+ * @description Whether the fdw_warehouse extension exists in the project database
+ * @example true
+ */
+ extension_installed: boolean
+ /**
+ * @description Whether the Warehouse foreign schema import has exposed the Warehouse snapshots table
+ * @example true
+ */
+ foreign_schema_imported: boolean
+ /**
+ * @description Whether the local Warehouse schema exists in the project database
+ * @example true
+ */
+ schema_created: boolean
+ /**
+ * @description Whether the Warehouse foreign server exists in the project database
+ * @example true
+ */
+ server_configured: boolean
+ /**
+ * @description Whether the Warehouse foreign data wrapper exists in the project database
+ * @example true
+ */
+ wrapper_installed: boolean
+ }
+ /**
+ * @description Warehouse replication pipeline id when it exists
+ * @example 101
+ */
+ pipeline_id?: number
+ /**
+ * @description Overall Warehouse setup status derived from replication state
+ * @example copying
+ * @enum {string}
+ */
+ setup_status: 'not_started' | 'setting_up' | 'copying' | 'complete' | 'error'
+ /** @description Warehouse setup phases in execution order */
+ steps: {
+ /**
+ * @description Best-effort progress or error message derived from Warehouse state
+ * @example Pending initial copy: public.orders:copying_table
+ */
+ message?: string
+ /**
+ * @description Observable Warehouse setup phase
+ * @example warehouse_copy
+ * @enum {string}
+ */
+ name: 'warehouse_pipeline' | 'warehouse_copy' | 'warehouse_fdw'
+ /**
+ * @description Derived Warehouse setup step status
+ * @example running
+ * @enum {string}
+ */
+ status: 'waiting' | 'running' | 'completed' | 'skipped' | 'error'
+ }[]
+ /** @description Warehouse linked tables and replication-derived sync state */
+ tables: {
+ /**
+ * @description Warehouse-facing table name
+ * @example warehouse.orders
+ */
+ copy_name: string
+ /**
+ * @description Replication lag in milliseconds, when available
+ * @example 12000
+ */
+ lag_ms?: number
+ /**
+ * Format: date-time
+ * @description Last sync timestamp, when available
+ * @example 2026-06-23T17:48:00Z
+ */
+ last_synced_at?: string
+ /**
+ * @description Postgres table name
+ * @example orders
+ */
+ name: string
+ /**
+ * @description Postgres schema name
+ * @example public
+ */
+ schema: string
+ /**
+ * @description Warehouse copy sync state derived from replication status
+ * @example live
+ * @enum {string}
+ */
+ state: 'syncing' | 'live' | 'error'
+ /**
+ * @description Warehouse table size in bytes, when available
+ * @example 197912092672
+ */
+ warehouse_size_bytes?: number
+ }[]
+ }
+ WarehouseTableSnapshotsResponse: {
+ /** @description Available Warehouse snapshots for the project catalog. */
+ snapshots: {
+ /**
+ * @description Snapshot author, when available.
+ * @example postgres
+ */
+ author: string | null
+ /** @description Snapshot change metadata returned by the Warehouse FDW. */
+ changes: string | null
+ /** @description Additional snapshot commit metadata returned by the Warehouse FDW. */
+ commit_extra_info: string | null
+ /** @description Snapshot commit message, when available. */
+ commit_message: string | null
+ /**
+ * @description DuckLake schema version. Returned as a string because the source value is bigint.
+ * @example 7
+ */
+ schema_version: string | null
+ /**
+ * @description DuckLake snapshot id. Returned as a string because the source value is bigint.
+ * @example 42
+ */
+ snapshot_id: string
+ /**
+ * @description Snapshot timestamp returned by the Warehouse FDW.
+ * @example 2026-06-24 08:00:00+00
+ */
+ snapshot_time: string | null
+ }[]
+ }
+ WarehouseTablesResponse: {
+ /** @description Tables with Warehouse copies */
+ tables: {
+ /**
+ * @description Warehouse-facing table name
+ * @example warehouse.orders
+ */
+ copy_name: string
+ /**
+ * @description Replication lag in milliseconds, when available
+ * @example 12000
+ */
+ lag_ms?: number
+ /**
+ * Format: date-time
+ * @description Last sync timestamp, when available
+ * @example 2026-06-23T17:48:00Z
+ */
+ last_synced_at?: string
+ /**
+ * @description Postgres table name
+ * @example orders
+ */
+ name: string
+ /**
+ * @description Postgres schema name
+ * @example public
+ */
+ schema: string
+ /**
+ * @description Warehouse copy sync state derived from replication status
+ * @example live
+ * @enum {string}
+ */
+ state: 'syncing' | 'live' | 'error'
+ /**
+ * @description Warehouse table size in bytes, when available
+ * @example 197912092672
+ */
+ warehouse_size_bytes?: number
+ }[]
+ }
+ WorkflowRunResponse: {
+ branch_id: string
+ check_run_id: number | null
+ created_at: string
+ git_config?: unknown
+ id: string
+ /** @enum {string} */
+ status:
+ | 'CREATING_PROJECT'
+ | 'RUNNING_MIGRATIONS'
+ | 'MIGRATIONS_PASSED'
+ | 'MIGRATIONS_FAILED'
+ | 'FUNCTIONS_DEPLOYED'
+ | 'FUNCTIONS_FAILED'
+ updated_at: string
+ workdir: string | null
+ }
+ }
+ responses: never
+ parameters: never
+ requestBodies: never
+ headers: never
+ pathItems: never
+}
+export type $defs = Record
+export interface operations {
+ GoTrueConfigController_getGoTrueConfig: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
headers: {
[name: string]: unknown
}
@@ -14791,7 +15143,7 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['CreateUserReponse']
+ 'application/json': components['schemas']['CreateUserResponse']
}
}
/** @description Unauthorized */
@@ -14827,8 +15179,12 @@ export interface operations {
UsersController_deleteUserById: {
parameters: {
query?: {
- /** @description Boolean string, true or false */
- soft_delete?: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ soft_delete?: string
}
header?: never
path: {
@@ -14898,7 +15254,7 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['UpdateUserReponse']
+ 'application/json': components['schemas']['UpdateUserResponse']
}
}
/** @description Unauthorized */
@@ -15587,7 +15943,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -15853,36 +16211,6 @@ export interface operations {
}
}
}
- SendFeedbackController_sendDocsFeedback: {
- parameters: {
- query?: never
- header?: never
- path?: never
- cookie?: never
- }
- requestBody: {
- content: {
- 'application/json': components['schemas']['SendDocsFeedbackBody']
- }
- }
- responses: {
- 201: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['SendFeedbackResponse']
- }
- }
- /** @description Failed to send feedback for docs */
- 500: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- }
- }
SendFeedbackController_sendExitSurvey: {
parameters: {
query?: never
@@ -16137,6 +16465,7 @@ export interface operations {
parameters: {
query: {
organization_id: number
+ project_ref?: string
}
header?: never
path?: never
@@ -16247,6 +16576,58 @@ export interface operations {
}
}
}
+ GitHubConnectionsController_getGitHubConnectionConfig: {
+ parameters: {
+ query?: {
+ /** @description Git branch, tag or commit SHA to read the config from. Defaults to the default branch of the connected repository. */
+ ref?: string
+ }
+ header?: never
+ path: {
+ connection_id: number
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['GetGitHubConnectionConfigResponse']
+ }
+ }
+ /** @description Not allowed to read the config of this connection */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description GitHub connection not found, or the repository has no config file */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description The config file could not be parsed as TOML */
+ 422: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to get the Supabase config of the connected GitHub repository */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
GitHubRepositoriesController_listRepositories: {
parameters: {
query?: never
@@ -16522,7 +16903,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -16582,7 +16965,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -17004,7 +17389,35 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['CreateOrganizationResponse']
+ 'application/json':
+ | {
+ pending_payment_intent_secret: string | null
+ }
+ | {
+ billing_email: string | null
+ billing_partner: ('aws_marketplace' | 'vercel_marketplace') | null
+ id: number
+ integration_source: string | null
+ is_owner: boolean
+ name: string
+ opt_in_tags: string[]
+ organization_missing_address: boolean
+ organization_missing_tax_id: boolean
+ organization_requires_mfa: boolean
+ plan: {
+ /** @enum {string} */
+ id: 'free' | 'pro' | 'team' | 'enterprise' | 'platform'
+ name: string
+ }
+ restriction_data: {
+ [key: string]: string
+ } | null
+ restriction_status: ('grace_period' | 'grace_period_over' | 'restricted') | null
+ slug: string
+ stripe_customer_id: string | null
+ subscription_id: string | null
+ usage_billing_enabled: boolean
+ }
}
}
/** @description Unexpected error creating an organization */
@@ -17247,7 +17660,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -19333,7 +19748,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Unauthorized */
401: {
@@ -19383,7 +19800,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Unauthorized */
401: {
@@ -19433,7 +19852,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Unauthorized */
401: {
@@ -19808,7 +20229,14 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['CreateInvitationResponse']
+ 'application/json': {
+ failed: {
+ /** Format: email */
+ email: string
+ error: string
+ }[]
+ succeeded: string[]
+ } | null
}
}
/** @description Unauthorized */
@@ -20036,7 +20464,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -20873,7 +21303,38 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['GetSSOProviderResponse']
+ 'application/json':
+ | {
+ /** @default [] */
+ domains: string[]
+ email_mapping: string[]
+ enabled: boolean
+ first_name_mapping?: string[]
+ idjag_issuer_url?: string | null
+ join_org_on_signup_enabled: boolean
+ /** @enum {string} */
+ join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
+ last_name_mapping?: string[]
+ metadata_xml_file: string
+ /** Format: uri */
+ metadata_xml_url?: string
+ user_name_mapping?: string[]
+ }
+ | {
+ /** @default [] */
+ domains: string[]
+ email_mapping: string[]
+ enabled: boolean
+ first_name_mapping?: string[]
+ idjag_issuer_url?: string | null
+ join_org_on_signup_enabled: boolean
+ /** @enum {string} */
+ join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
+ last_name_mapping?: string[]
+ metadata_xml_file?: string
+ metadata_xml_url: string
+ user_name_mapping?: string[]
+ }
}
}
/** @description Unauthorized */
@@ -20920,7 +21381,38 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['UpdateSSOProviderResponse']
+ 'application/json':
+ | {
+ /** @default [] */
+ domains: string[]
+ email_mapping: string[]
+ enabled: boolean
+ first_name_mapping?: string[]
+ idjag_issuer_url?: string | null
+ join_org_on_signup_enabled: boolean
+ /** @enum {string} */
+ join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
+ last_name_mapping?: string[]
+ metadata_xml_file: string
+ /** Format: uri */
+ metadata_xml_url?: string
+ user_name_mapping?: string[]
+ }
+ | {
+ /** @default [] */
+ domains: string[]
+ email_mapping: string[]
+ enabled: boolean
+ first_name_mapping?: string[]
+ idjag_issuer_url?: string | null
+ join_org_on_signup_enabled: boolean
+ /** @enum {string} */
+ join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
+ last_name_mapping?: string[]
+ metadata_xml_file?: string
+ metadata_xml_url: string
+ user_name_mapping?: string[]
+ }
}
}
/** @description Unauthorized */
@@ -20967,7 +21459,38 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['CreateSSOProviderResponse']
+ 'application/json':
+ | {
+ /** @default [] */
+ domains: string[]
+ email_mapping: string[]
+ enabled: boolean
+ first_name_mapping?: string[]
+ idjag_issuer_url?: string | null
+ join_org_on_signup_enabled: boolean
+ /** @enum {string} */
+ join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
+ last_name_mapping?: string[]
+ metadata_xml_file: string
+ /** Format: uri */
+ metadata_xml_url?: string
+ user_name_mapping?: string[]
+ }
+ | {
+ /** @default [] */
+ domains: string[]
+ email_mapping: string[]
+ enabled: boolean
+ first_name_mapping?: string[]
+ idjag_issuer_url?: string | null
+ join_org_on_signup_enabled: boolean
+ /** @enum {string} */
+ join_org_on_signup_role?: 'Administrator' | 'Developer' | 'Owner' | 'Read-only'
+ last_name_mapping?: string[]
+ metadata_xml_file?: string
+ metadata_xml_url: string
+ user_name_mapping?: string[]
+ }
}
}
/** @description Unauthorized */
@@ -20982,7 +21505,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -21091,108 +21616,6 @@ export interface operations {
}
}
}
- TaxIdsController_updateTaxId: {
- parameters: {
- query?: never
- header?: never
- path: {
- /** @description Organization slug */
- slug: string
- }
- cookie?: never
- }
- requestBody: {
- content: {
- 'application/json': components['schemas']['CreateTaxIdBody']
- }
- }
- responses: {
- 200: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['TaxIdResponse']
- }
- }
- /** @description Unauthorized */
- 401: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Forbidden action */
- 403: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Rate limit exceeded */
- 429: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Failed to create the tax ID */
- 500: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- }
- }
- TaxIdsController_deleteTaxId: {
- parameters: {
- query?: never
- header?: never
- path: {
- /** @description Organization slug */
- slug: string
- }
- cookie?: never
- }
- requestBody?: never
- responses: {
- 204: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Unauthorized */
- 401: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Forbidden action */
- 403: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Rate limit exceeded */
- 429: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Failed to delete the tax ID */
- 500: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- }
- }
OrgUsageController_getOrgUsage: {
parameters: {
query?: {
@@ -21351,7 +21774,35 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['CreateOrganizationResponse']
+ 'application/json':
+ | {
+ pending_payment_intent_secret: string | null
+ }
+ | {
+ billing_email: string | null
+ billing_partner: ('aws_marketplace' | 'vercel_marketplace') | null
+ id: number
+ integration_source: string | null
+ is_owner: boolean
+ name: string
+ opt_in_tags: string[]
+ organization_missing_address: boolean
+ organization_missing_tax_id: boolean
+ organization_requires_mfa: boolean
+ plan: {
+ /** @enum {string} */
+ id: 'free' | 'pro' | 'team' | 'enterprise' | 'platform'
+ name: string
+ }
+ restriction_data: {
+ [key: string]: string
+ } | null
+ restriction_status: ('grace_period' | 'grace_period_over' | 'restricted') | null
+ slug: string
+ stripe_customer_id: string | null
+ subscription_id: string | null
+ usage_billing_enabled: boolean
+ }
}
}
202: {
@@ -22064,6 +22515,7 @@ export interface operations {
| 'storage.image_transformations'
| 'storage.vector_buckets'
| 'storage.iceberg_catalog'
+ | 'storage.purge_cache'
| 'security.audit_logs_days'
| 'security.questionnaire'
| 'security.soc2_report'
@@ -22113,6 +22565,8 @@ export interface operations {
| 'integrations.github_connections'
| 'dedicated_pooler'
| 'observability.dashboard_advanced_metrics'
+ | 'api.members.invitations'
+ | 'api.members.roles'
}
header?: never
path?: never
@@ -22726,9 +23180,9 @@ export interface operations {
ApiKeysLastUsedController_getApiKeysLastUsed: {
parameters: {
query?: {
- iso_timestamp_start?: string
- iso_timestamp_end?: string
days?: string
+ iso_timestamp_end?: string
+ iso_timestamp_start?: string
}
header?: never
path: {
@@ -22988,6 +23442,115 @@ export interface operations {
}
}
}
+ LogsController_getProjectLogsViaGetNew: {
+ parameters: {
+ query?: {
+ iso_timestamp_end?: string
+ iso_timestamp_start?: string
+ lql?: string
+ sql?: string
+ }
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['AnalyticsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to get project's logs */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ LogsController_getProjectLogsViaPostNew: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['GetProjectLogsBody']
+ }
+ }
+ responses: {
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['AnalyticsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to get project's logs */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
LogsController_getProjectLogsViaGet: {
parameters: {
query?: {
@@ -23554,7 +24117,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -23793,11 +24358,11 @@ export interface operations {
}
}
}
- ApiKeysController_createTemporaryApiKey: {
+ 'scrape-project-metrics': {
parameters: {
- query: {
- authorization_exp: string
- claims: string
+ query?: {
+ /** @description Project service to include in the scrape. Valid values are `database`. Defaults to `database`. */
+ services?: string
}
header?: never
path: {
@@ -23808,13 +24373,68 @@ export interface operations {
}
requestBody?: never
responses: {
- /** @description Temporary API key */
- 201: {
+ /** @description Prometheus / OpenMetrics text exposition */
+ 200: {
headers: {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['TemporaryApiKeyResponse']
+ 'application/openmetrics-text': string
+ 'text/plain': string
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to fetch project's metrics */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ ApiKeysController_createTemporaryApiKey: {
+ parameters: {
+ query: {
+ authorization_exp: string
+ claims: string
+ }
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Temporary API key */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['TemporaryApiKeyResponse']
}
}
/** @description Unauthorized */
@@ -24778,8 +25398,12 @@ export interface operations {
parameters: {
query?: {
cursor?: string
- /** @description Boolean string, true or false */
- favorite?: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ favorite?: string
limit?: string
name?: string
sort_by?: 'name' | 'inserted_at'
@@ -25847,65 +26471,68 @@ export interface operations {
| 'physical_replication_lag_physical_replication_lag_seconds'
| 'pg_stat_database_num_backends'
| 'max_db_connections'
- attributes?: (
- | 'cpu_usage'
- | 'cpu_usage_busy_system'
- | 'cpu_usage_busy_user'
- | 'cpu_usage_busy_iowait'
- | 'cpu_usage_busy_irqs'
- | 'cpu_usage_busy_other'
- | 'cpu_usage_busy_idle'
- | 'max_cpu_usage'
- | 'avg_cpu_usage'
- | 'ram_usage'
- | 'ram_usage_total'
- | 'ram_usage_available'
- | 'ram_usage_used'
- | 'ram_usage_free'
- | 'ram_usage_cache_and_buffers'
- | 'ram_usage_swap'
- | 'ram_commit_used'
- | 'ram_commit_limit'
- | 'swap_usage'
- | 'client_connections_pgbouncer'
- | 'network_receive_bytes'
- | 'network_transmit_bytes'
- | 'pgbouncer_pools_client_active_connections'
- | 'supavisor_connections_active'
- | 'client_connections_postgres'
- | 'client_connections_authenticator'
- | 'client_connections_supabase_auth_admin'
- | 'client_connections_supabase_storage_admin'
- | 'client_connections_supabase_admin'
- | 'client_connections_other'
- | 'realtime_connections_connected'
- | 'realtime_channel_joins'
- | 'realtime_channel_events'
- | 'realtime_channel_presence_events'
- | 'realtime_channel_db_events'
- | 'realtime_authorization_rls_execution_time'
- | 'realtime_read_authorization_rls_execution_time'
- | 'realtime_write_authorization_rls_execution_time'
- | 'realtime_payload_size'
- | 'realtime_replication_connection_lag'
- | 'realtime_sum_connections_connected'
- | 'disk_io_budget'
- | 'disk_io_consumption'
- | 'disk_io_usage'
- | 'disk_iops_read'
- | 'disk_iops_write'
- | 'disk_bytes_read'
- | 'disk_bytes_written'
- | 'pg_database_size'
- | 'disk_fs_size'
- | 'disk_fs_avail'
- | 'disk_fs_used'
- | 'disk_fs_used_wal'
- | 'disk_fs_used_system'
- | 'physical_replication_lag_physical_replication_lag_seconds'
- | 'pg_stat_database_num_backends'
- | 'max_db_connections'
- )[]
+ /** @description Comma-separated list of enums or array of enums. */
+ attributes?:
+ | string
+ | (
+ | 'cpu_usage'
+ | 'cpu_usage_busy_system'
+ | 'cpu_usage_busy_user'
+ | 'cpu_usage_busy_iowait'
+ | 'cpu_usage_busy_irqs'
+ | 'cpu_usage_busy_other'
+ | 'cpu_usage_busy_idle'
+ | 'max_cpu_usage'
+ | 'avg_cpu_usage'
+ | 'ram_usage'
+ | 'ram_usage_total'
+ | 'ram_usage_available'
+ | 'ram_usage_used'
+ | 'ram_usage_free'
+ | 'ram_usage_cache_and_buffers'
+ | 'ram_usage_swap'
+ | 'ram_commit_used'
+ | 'ram_commit_limit'
+ | 'swap_usage'
+ | 'client_connections_pgbouncer'
+ | 'network_receive_bytes'
+ | 'network_transmit_bytes'
+ | 'pgbouncer_pools_client_active_connections'
+ | 'supavisor_connections_active'
+ | 'client_connections_postgres'
+ | 'client_connections_authenticator'
+ | 'client_connections_supabase_auth_admin'
+ | 'client_connections_supabase_storage_admin'
+ | 'client_connections_supabase_admin'
+ | 'client_connections_other'
+ | 'realtime_connections_connected'
+ | 'realtime_channel_joins'
+ | 'realtime_channel_events'
+ | 'realtime_channel_presence_events'
+ | 'realtime_channel_db_events'
+ | 'realtime_authorization_rls_execution_time'
+ | 'realtime_read_authorization_rls_execution_time'
+ | 'realtime_write_authorization_rls_execution_time'
+ | 'realtime_payload_size'
+ | 'realtime_replication_connection_lag'
+ | 'realtime_sum_connections_connected'
+ | 'disk_io_budget'
+ | 'disk_io_consumption'
+ | 'disk_io_usage'
+ | 'disk_iops_read'
+ | 'disk_iops_write'
+ | 'disk_bytes_read'
+ | 'disk_bytes_written'
+ | 'pg_database_size'
+ | 'disk_fs_size'
+ | 'disk_fs_avail'
+ | 'disk_fs_used'
+ | 'disk_fs_used_wal'
+ | 'disk_fs_used_system'
+ | 'physical_replication_lag_physical_replication_lag_seconds'
+ | 'pg_stat_database_num_backends'
+ | 'max_db_connections'
+ )[]
databaseIdentifier?: string
endDate: string
interval?: '1m' | '5m' | '10m' | '30m' | '1h' | '1d'
@@ -26432,7 +27059,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -26514,6 +27143,64 @@ export interface operations {
}
}
}
+ ProjectPrivateLinkController_removeAwsAccountFromPrivateLinkForDatabase: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ aws_account_id: string
+ database_identifier: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Scheduled AWS PrivateLink resources to be removed. */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Invalid AWS account ID format or association does not have a valid status for deletion. */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to remove AWS account from PrivateLink share */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
ResizeController_resizeDatabase: {
parameters: {
query?: never
@@ -26548,7 +27235,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -26824,41 +27513,11 @@ export interface operations {
}
}
}
- ProjectRunLintsController_runLintByName: {
+ ProjectServiceVersionsController_getServiceVersions: {
parameters: {
query?: never
header?: never
path: {
- name:
- | 'unindexed_foreign_keys'
- | 'auth_users_exposed'
- | 'auth_rls_initplan'
- | 'no_primary_key'
- | 'unused_index'
- | 'multiple_permissive_policies'
- | 'policy_exists_rls_disabled'
- | 'rls_enabled_no_policy'
- | 'duplicate_index'
- | 'security_definer_view'
- | 'function_search_path_mutable'
- | 'rls_disabled_in_public'
- | 'extension_in_public'
- | 'rls_references_user_metadata'
- | 'materialized_view_in_api'
- | 'foreign_table_in_api'
- | 'unsupported_reg_types'
- | 'auth_otp_long_expiry'
- | 'auth_otp_short_length'
- | 'ssl_not_enforced'
- | 'network_restrictions_not_set'
- | 'password_requirements_min_length'
- | 'pitr_not_enabled'
- | 'auth_leaked_password_protection'
- | 'auth_insufficient_mfa_options'
- | 'auth_password_policy_missing'
- | 'leaked_service_key'
- | 'no_backup_admin'
- | 'vulnerable_postgres_version'
/** @description Project ref */
ref: string
}
@@ -26871,7 +27530,7 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['RunLintByNameResponse']
+ 'application/json': components['schemas']['ServiceVersions']
}
}
/** @description Unauthorized */
@@ -26897,7 +27556,7 @@ export interface operations {
}
}
}
- ProjectRunLintsController_runLeakedServiceKeyLint: {
+ SettingsController_getProjectSettings: {
parameters: {
query?: never
header?: never
@@ -26914,7 +27573,7 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['GetLeakedServiceKeyLintResponse']
+ 'application/json': components['schemas']['ProjectSettingsResponse']
}
}
/** @description Unauthorized */
@@ -26938,9 +27597,16 @@ export interface operations {
}
content?: never
}
+ /** @description Failed to retrieve project's settings */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
}
}
- ProjectRunLintsController_runAuthBackupAdminLint: {
+ SensitivityController_updateProjectSensitivity: {
parameters: {
query?: never
header?: never
@@ -26950,14 +27616,18 @@ export interface operations {
}
cookie?: never
}
- requestBody?: never
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['MarkSensitiveBody']
+ }
+ }
responses: {
200: {
headers: {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['AuthBackupAdminLintResponse']
+ 'application/json': components['schemas']['ProjectSensitivityResponse']
}
}
/** @description Unauthorized */
@@ -26981,9 +27651,16 @@ export interface operations {
}
content?: never
}
+ /** @description Failed to update project */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
}
}
- ProjectServiceVersionsController_getServiceVersions: {
+ ProjectStatusController_getStatus: {
parameters: {
query?: never
header?: never
@@ -26999,9 +27676,7 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content: {
- 'application/json': components['schemas']['ServiceVersions']
- }
+ content?: never
}
/** @description Unauthorized */
401: {
@@ -27024,9 +27699,16 @@ export interface operations {
}
content?: never
}
+ /** @description Failed to get project's status */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
}
}
- SettingsController_getProjectSettings: {
+ ProjectTransferController_transferProject: {
parameters: {
query?: never
header?: never
@@ -27036,15 +27718,17 @@ export interface operations {
}
cookie?: never
}
- requestBody?: never
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['TransferProjectBody']
+ }
+ }
responses: {
- 200: {
+ 201: {
headers: {
[name: string]: unknown
}
- content: {
- 'application/json': components['schemas']['ProjectSettingsResponse']
- }
+ content?: never
}
/** @description Unauthorized */
401: {
@@ -27067,16 +27751,9 @@ export interface operations {
}
content?: never
}
- /** @description Failed to retrieve project's settings */
- 500: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
}
}
- SensitivityController_updateProjectSensitivity: {
+ ProjectTransferController_previewTransfer: {
parameters: {
query?: never
header?: never
@@ -27088,16 +27765,16 @@ export interface operations {
}
requestBody: {
content: {
- 'application/json': components['schemas']['MarkSensitiveBody']
+ 'application/json': components['schemas']['TransferProjectBody']
}
}
responses: {
- 200: {
+ 201: {
headers: {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['ProjectSensitivityResponse']
+ 'application/json': components['schemas']['PreviewProjectTransferResponse']
}
}
/** @description Unauthorized */
@@ -27121,156 +27798,9 @@ export interface operations {
}
content?: never
}
- /** @description Failed to update project */
- 500: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
}
}
- ProjectStatusController_getStatus: {
- parameters: {
- query?: never
- header?: never
- path: {
- /** @description Project ref */
- ref: string
- }
- cookie?: never
- }
- requestBody?: never
- responses: {
- 200: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Unauthorized */
- 401: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Forbidden action */
- 403: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Rate limit exceeded */
- 429: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Failed to get project's status */
- 500: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- }
- }
- ProjectTransferController_transferProject: {
- parameters: {
- query?: never
- header?: never
- path: {
- /** @description Project ref */
- ref: string
- }
- cookie?: never
- }
- requestBody: {
- content: {
- 'application/json': components['schemas']['TransferProjectBody']
- }
- }
- responses: {
- 201: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Unauthorized */
- 401: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Forbidden action */
- 403: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Rate limit exceeded */
- 429: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- }
- }
- ProjectTransferController_previewTransfer: {
- parameters: {
- query?: never
- header?: never
- path: {
- /** @description Project ref */
- ref: string
- }
- cookie?: never
- }
- requestBody: {
- content: {
- 'application/json': components['schemas']['TransferProjectBody']
- }
- }
- responses: {
- 201: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['PreviewProjectTransferResponse']
- }
- }
- /** @description Unauthorized */
- 401: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Forbidden action */
- 403: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- /** @description Rate limit exceeded */
- 429: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- }
- }
- ProjectWakeController_wakeUpProject: {
+ ProjectWakeController_wakeUpProject: {
parameters: {
query?: never
header?: never
@@ -27316,7 +27846,7 @@ export interface operations {
ProjectsController_getRegions: {
parameters: {
query: {
- cloud_provider: 'AWS' | 'FLY' | 'AWS_K8S' | 'AWS_NIMBUS'
+ cloud_provider: 'AWS' | 'AWS_K8S' | 'AWS_NIMBUS'
desired_instance_size?:
| 'micro'
| 'small'
@@ -27437,6 +27967,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -27492,6 +28031,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -27549,6 +28097,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -27604,6 +28161,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -27726,6 +28292,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -27777,6 +28352,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -27952,6 +28536,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28060,6 +28653,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28111,6 +28713,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28201,7 +28812,7 @@ export interface operations {
}
}
}
- ReplicationPipelinesController_rollbackTables: {
+ ReplicationPipelinesController_restartPipeline: {
parameters: {
query?: never
header?: never
@@ -28213,20 +28824,14 @@ export interface operations {
}
cookie?: never
}
- requestBody: {
- content: {
- 'application/json': components['schemas']['RollbackTablesBody']
- }
- }
+ requestBody?: never
responses: {
- /** @description New table states after rollback. */
- 200: {
+ /** @description Pipeline restart accepted. */
+ 202: {
headers: {
[name: string]: unknown
}
- content: {
- 'application/json': components['schemas']['RollbackTablesResponse']
- }
+ content?: never
}
/** @description Unauthorized */
401: {
@@ -28235,6 +28840,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28242,6 +28856,13 @@ export interface operations {
}
content?: never
}
+ /** @description Pipeline is not running. */
+ 409: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
/** @description Rate limit exceeded */
429: {
headers: {
@@ -28249,7 +28870,7 @@ export interface operations {
}
content?: never
}
- /** @description Unexpected error while rolling back tables. */
+ /** @description Unexpected error while restarting pipeline. */
500: {
headers: {
[name: string]: unknown
@@ -28258,7 +28879,7 @@ export interface operations {
}
}
}
- ReplicationPipelinesController_startPipeline: {
+ ReplicationPipelinesController_rollbackTables: {
parameters: {
query?: never
header?: never
@@ -28270,22 +28891,37 @@ export interface operations {
}
cookie?: never
}
- requestBody?: never
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['RollbackTablesBody']
+ }
+ }
responses: {
- /** @description Pipeline started. */
+ /** @description New table states after rollback. */
200: {
headers: {
[name: string]: unknown
}
- content?: never
- }
- /** @description Unauthorized */
+ content: {
+ 'application/json': components['schemas']['RollbackTablesResponse']
+ }
+ }
+ /** @description Unauthorized */
401: {
headers: {
[name: string]: unknown
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28300,7 +28936,7 @@ export interface operations {
}
content?: never
}
- /** @description Unexpected error while starting pipeline. */
+ /** @description Unexpected error while rolling back tables. */
500: {
headers: {
[name: string]: unknown
@@ -28309,7 +28945,7 @@ export interface operations {
}
}
}
- ReplicationPipelinesController_restartPipeline: {
+ ReplicationPipelinesController_startPipeline: {
parameters: {
query?: never
header?: never
@@ -28323,8 +28959,8 @@ export interface operations {
}
requestBody?: never
responses: {
- /** @description Pipeline restart accepted. */
- 202: {
+ /** @description Pipeline started. */
+ 200: {
headers: {
[name: string]: unknown
}
@@ -28337,15 +28973,17 @@ export interface operations {
}
content?: never
}
- /** @description Forbidden action */
- 403: {
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
- /** @description Pipeline is not running. */
- 409: {
+ /** @description Forbidden action */
+ 403: {
headers: {
[name: string]: unknown
}
@@ -28358,7 +28996,7 @@ export interface operations {
}
content?: never
}
- /** @description Unexpected error while restarting pipeline. */
+ /** @description Unexpected error while starting pipeline. */
500: {
headers: {
[name: string]: unknown
@@ -28448,6 +29086,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28556,6 +29203,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28718,7 +29374,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -28796,13 +29454,11 @@ export interface operations {
}
}
}
- ReplicationSourcesController_getCostEstimate: {
+ ReplicationSourcesController_createPublication: {
parameters: {
query?: never
header?: never
path: {
- /** @description Publication name */
- publication_name: string
/** @description Project ref */
ref: string
/** @description Source id */
@@ -28810,16 +29466,18 @@ export interface operations {
}
cookie?: never
}
- requestBody?: never
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['CreateReplicationPublicationBody']
+ }
+ }
responses: {
- /** @description Cost estimate for replicating the publication. */
+ /** @description Publication created. */
200: {
headers: {
[name: string]: unknown
}
- content: {
- 'application/json': components['schemas']['CostEstimateResponse']
- }
+ content?: never
}
/** @description Unauthorized */
401: {
@@ -28828,6 +29486,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28842,7 +29509,7 @@ export interface operations {
}
content?: never
}
- /** @description Unexpected error while estimating replication cost. */
+ /** @description Unexpected error while creating publication. */
500: {
headers: {
[name: string]: unknown
@@ -28851,11 +29518,13 @@ export interface operations {
}
}
}
- ReplicationSourcesController_createPublication: {
+ ReplicationSourcesController_updatePublication: {
parameters: {
query?: never
header?: never
path: {
+ /** @description Publication name */
+ publication_name: string
/** @description Project ref */
ref: string
/** @description Source id */
@@ -28865,11 +29534,11 @@ export interface operations {
}
requestBody: {
content: {
- 'application/json': components['schemas']['CreateReplicationPublicationBody']
+ 'application/json': components['schemas']['UpdateReplicationPublicationBody']
}
}
responses: {
- /** @description Publication created. */
+ /** @description Publication updated. */
200: {
headers: {
[name: string]: unknown
@@ -28883,6 +29552,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28897,7 +29575,7 @@ export interface operations {
}
content?: never
}
- /** @description Unexpected error while creating publication. */
+ /** @description Unexpected error while updating publication. */
500: {
headers: {
[name: string]: unknown
@@ -28906,7 +29584,7 @@ export interface operations {
}
}
}
- ReplicationSourcesController_updatePublication: {
+ ReplicationSourcesController_deletePublication: {
parameters: {
query?: never
header?: never
@@ -28920,13 +29598,9 @@ export interface operations {
}
cookie?: never
}
- requestBody: {
- content: {
- 'application/json': components['schemas']['UpdateReplicationPublicationBody']
- }
- }
+ requestBody?: never
responses: {
- /** @description Publication updated. */
+ /** @description Publication deleted. */
200: {
headers: {
[name: string]: unknown
@@ -28940,6 +29614,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -28947,6 +29630,13 @@ export interface operations {
}
content?: never
}
+ /** @description Source not found. */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
/** @description Rate limit exceeded */
429: {
headers: {
@@ -28954,7 +29644,7 @@ export interface operations {
}
content?: never
}
- /** @description Unexpected error while updating publication. */
+ /** @description Unexpected error while deleting publication. */
500: {
headers: {
[name: string]: unknown
@@ -28963,7 +29653,7 @@ export interface operations {
}
}
}
- ReplicationSourcesController_deletePublication: {
+ ReplicationSourcesController_getCostEstimate: {
parameters: {
query?: never
header?: never
@@ -28979,12 +29669,14 @@ export interface operations {
}
requestBody?: never
responses: {
- /** @description Publication deleted. */
+ /** @description Cost estimate for replicating the publication. */
200: {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['CostEstimateResponse']
+ }
}
/** @description Unauthorized */
401: {
@@ -29000,13 +29692,6 @@ export interface operations {
}
content?: never
}
- /** @description Source not found. */
- 404: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
/** @description Rate limit exceeded */
429: {
headers: {
@@ -29014,7 +29699,7 @@ export interface operations {
}
content?: never
}
- /** @description Unexpected error while deleting publication. */
+ /** @description Unexpected error while estimating replication cost. */
500: {
headers: {
[name: string]: unknown
@@ -29102,6 +29787,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -29172,7 +29866,9 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
}
/** @description Forbidden action */
403: {
@@ -29383,7 +30079,7 @@ export interface operations {
query?: never
header?: never
path: {
- /** @description Analytics Bucket ID */
+ /** @description Storage bucket id */
id: string
/** @description Project ref */
ref: string
@@ -29435,7 +30131,7 @@ export interface operations {
query?: never
header?: never
path: {
- /** @description Analytics Bucket ID */
+ /** @description Storage bucket id */
id: string
/** @description Project ref */
ref: string
@@ -29487,7 +30183,7 @@ export interface operations {
query?: never
header?: never
path: {
- /** @description Analytics Bucket ID */
+ /** @description Storage bucket id */
id: string
/** @description Project ref */
ref: string
@@ -29700,8 +30396,12 @@ export interface operations {
StorageAnalyticsBucketNamespaceTableController_dropTable: {
parameters: {
query?: {
- /** @description Boolean string, true or false */
- purge?: boolean
+ /** @description Boolean string.
+ *
+ * Truthy values: `true`, `1`, `yes`, `on`, `y`, `enabled`
+ *
+ * Falsy values: `false`, `0`, `no`, `off`, `n`, `disabled` */
+ purge?: string
}
header?: never
path: {
@@ -30608,7 +31308,7 @@ export interface operations {
}
}
}
- StorageS3CredentialsController_getAllCredentials: {
+ StorageCdnController_purgeBucketCache: {
parameters: {
query?: never
header?: never
@@ -30618,15 +31318,17 @@ export interface operations {
}
cookie?: never
}
- requestBody?: never
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['PurgeBucketCacheBody']
+ }
+ }
responses: {
- 200: {
+ 201: {
headers: {
[name: string]: unknown
}
- content: {
- 'application/json': components['schemas']['GetStorageCredentialsResponse']
- }
+ content?: never
}
/** @description Unauthorized */
401: {
@@ -30635,6 +31337,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -30649,7 +31360,7 @@ export interface operations {
}
content?: never
}
- /** @description Failed to get project storage credentials */
+ /** @description Failed to purge CDN cache for bucket */
500: {
headers: {
[name: string]: unknown
@@ -30658,7 +31369,7 @@ export interface operations {
}
}
}
- StorageS3CredentialsController_createCredential: {
+ StorageCdnController_purgeObjectCache: {
parameters: {
query?: never
header?: never
@@ -30670,7 +31381,7 @@ export interface operations {
}
requestBody: {
content: {
- 'application/json': components['schemas']['CreateStorageCredentialBody']
+ 'application/json': components['schemas']['PurgeObjectCacheBody']
}
}
responses: {
@@ -30678,9 +31389,7 @@ export interface operations {
headers: {
[name: string]: unknown
}
- content: {
- 'application/json': components['schemas']['CreateStorageCredentialResponse']
- }
+ content?: never
}
/** @description Unauthorized */
401: {
@@ -30689,6 +31398,15 @@ export interface operations {
}
content?: never
}
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
/** @description Forbidden action */
403: {
headers: {
@@ -30703,7 +31421,7 @@ export interface operations {
}
content?: never
}
- /** @description Failed to create project storage credential */
+ /** @description Failed to purge CDN cache for object */
500: {
headers: {
[name: string]: unknown
@@ -30712,13 +31430,11 @@ export interface operations {
}
}
}
- StorageS3CredentialsController_deleteCredential: {
+ StorageS3CredentialsController_getAllCredentials: {
parameters: {
query?: never
header?: never
path: {
- /** @description Storage credential id */
- id: string
/** @description Project ref */
ref: string
}
@@ -30726,11 +31442,13 @@ export interface operations {
}
requestBody?: never
responses: {
- 204: {
+ 200: {
headers: {
[name: string]: unknown
}
- content?: never
+ content: {
+ 'application/json': components['schemas']['GetStorageCredentialsResponse']
+ }
}
/** @description Unauthorized */
401: {
@@ -30753,7 +31471,7 @@ export interface operations {
}
content?: never
}
- /** @description Failed to delete project storage credential */
+ /** @description Failed to get project storage credentials */
500: {
headers: {
[name: string]: unknown
@@ -30762,11 +31480,9 @@ export interface operations {
}
}
}
- StorageVectorBucketsController_getBuckets: {
+ StorageS3CredentialsController_createCredential: {
parameters: {
- query?: {
- nextToken?: string
- }
+ query?: never
header?: never
path: {
/** @description Project ref */
@@ -30774,14 +31490,18 @@ export interface operations {
}
cookie?: never
}
- requestBody?: never
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['CreateStorageCredentialBody']
+ }
+ }
responses: {
- 200: {
+ 201: {
headers: {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['StorageVectorBucketsResponse']
+ 'application/json': components['schemas']['CreateStorageCredentialResponse']
}
}
/** @description Unauthorized */
@@ -30805,7 +31525,7 @@ export interface operations {
}
content?: never
}
- /** @description Failed to get list of vector buckets */
+ /** @description Failed to create project storage credential */
500: {
headers: {
[name: string]: unknown
@@ -30814,23 +31534,21 @@ export interface operations {
}
}
}
- StorageVectorBucketsController_createBucket: {
+ StorageS3CredentialsController_deleteCredential: {
parameters: {
query?: never
header?: never
path: {
+ /** @description Storage credential id */
+ id: string
/** @description Project ref */
ref: string
}
cookie?: never
}
- requestBody: {
- content: {
- 'application/json': components['schemas']['CreateStorageVectorBucketBody']
- }
- }
+ requestBody?: never
responses: {
- 201: {
+ 204: {
headers: {
[name: string]: unknown
}
@@ -30857,7 +31575,7 @@ export interface operations {
}
content?: never
}
- /** @description Failed to create vector bucket */
+ /** @description Failed to delete project storage credential */
500: {
headers: {
[name: string]: unknown
@@ -30866,12 +31584,13 @@ export interface operations {
}
}
}
- StorageVectorBucketIdController_getBucket: {
+ StorageVectorBucketsController_getBuckets: {
parameters: {
- query?: never
+ query?: {
+ nextToken?: string
+ }
header?: never
path: {
- id: string
/** @description Project ref */
ref: string
}
@@ -30884,7 +31603,7 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['StorageVectorBucketResponse']
+ 'application/json': components['schemas']['StorageVectorBucketsResponse']
}
}
/** @description Unauthorized */
@@ -30908,7 +31627,7 @@ export interface operations {
}
content?: never
}
- /** @description Failed to get bucket */
+ /** @description Failed to get list of vector buckets */
500: {
headers: {
[name: string]: unknown
@@ -30917,19 +31636,122 @@ export interface operations {
}
}
}
- StorageVectorBucketIdController_deleteBucket: {
+ StorageVectorBucketsController_createBucket: {
parameters: {
query?: never
header?: never
path: {
- id: string
/** @description Project ref */
ref: string
}
cookie?: never
}
- requestBody?: never
- responses: {
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['CreateStorageVectorBucketBody']
+ }
+ }
+ responses: {
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to create vector bucket */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ StorageVectorBucketIdController_getBucket: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['StorageVectorBucketResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Failed to get bucket */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ StorageVectorBucketIdController_deleteBucket: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
200: {
headers: {
[name: string]: unknown
@@ -31500,6 +32322,465 @@ export interface operations {
}
}
}
+ WarehouseController_getCatalog: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Warehouse catalog access. */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['WarehouseCatalogResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while retrieving Warehouse catalog. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ WarehouseController_updateCatalog: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['UpdateWarehouseCatalogBody']
+ }
+ }
+ responses: {
+ /** @description Warehouse catalog access updated. */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['WarehouseCatalogResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while updating Warehouse catalog. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ WarehouseController_refreshSchema: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Warehouse foreign schema refresh accepted. */
+ 202: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while refreshing the Warehouse foreign schema. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ WarehouseController_getSetupStatus: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Warehouse setup status. */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['WarehouseSetupStatusResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while retrieving Warehouse setup status. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ WarehouseController_getTables: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Warehouse linked tables. */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['WarehouseTablesResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while listing Warehouse tables. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ WarehouseController_linkTable: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['WarehouseLinkTableBody']
+ }
+ }
+ responses: {
+ /** @description Warehouse table link accepted. */
+ 202: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['WarehouseLinkedTable']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while linking Warehouse table. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ WarehouseController_detachTable: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Postgres table name */
+ name: string
+ /** @description Project ref */
+ ref: string
+ /** @description Postgres schema name */
+ schema: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Warehouse table detached. */
+ 204: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['PlanGateErrorBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while detaching Warehouse table. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
+ WarehouseController_getTableSnapshots: {
+ parameters: {
+ query?: {
+ /** @description Maximum number of snapshots to return. */
+ limit?: number
+ }
+ header?: never
+ path: {
+ /** @description Postgres table name */
+ name: string
+ /** @description Project ref */
+ ref: string
+ /** @description Postgres schema name */
+ schema: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Warehouse snapshots. */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['WarehouseTableSnapshotsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unexpected error while listing Warehouse snapshots. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ }
+ }
WorkflowRunController_listWorkflowRuns: {
parameters: {
query?: {
From 628c7e08d6b0f7ab154bb34d05bee74a06c1e466 Mon Sep 17 00:00:00 2001
From: Ivan Vasilov
Date: Thu, 13 Aug 2026 11:17:18 +0200
Subject: [PATCH 4/6] Add generation for v2 APIs. (#48983)
## Summary by CodeRabbit
* **New Features**
* Added comprehensive type support for API v1, API v2, and platform
endpoints.
* Improved access to API v2 webhook and schema definitions.
* Enabled separate type outputs for API v1 and API v2, making
version-specific integrations easier to manage.
* **Improvements**
* Updated shared API types to combine definitions across supported API
versions and platform services.
---
packages/api-types/index.ts | 41 +-
packages/api-types/redocly.yaml | 10 +-
.../api-types/types/{api.d.ts => api-v1.d.ts} | 0
packages/api-types/types/api-v2.d.ts | 12062 ++++++++++++++++
packages/api-types/types/platform.d.ts | 13 +
5 files changed, 12109 insertions(+), 17 deletions(-)
rename packages/api-types/types/{api.d.ts => api-v1.d.ts} (100%)
create mode 100644 packages/api-types/types/api-v2.d.ts
diff --git a/packages/api-types/index.ts b/packages/api-types/index.ts
index 4870d902de659..9c89e97947a55 100644
--- a/packages/api-types/index.ts
+++ b/packages/api-types/index.ts
@@ -1,25 +1,38 @@
import type {
- components as apiComponents,
- operations as apiOperations,
- paths as apiPaths,
-} from './types/api'
+ components as apiV1Components,
+ operations as apiV1Operations,
+ paths as apiV1Paths,
+} from './types/api-v1'
+import type {
+ components as apiV2Components,
+ operations as apiV2Operations,
+ paths as apiV2Paths,
+} from './types/api-v2'
import type {
components as platformComponents,
operations as platformOperations,
paths as platformPaths,
} from './types/platform'
-export type { webhooks, $defs } from './types/api'
+export type { webhooks, $defs } from './types/api-v2'
-export interface paths extends apiPaths, platformPaths {}
-export interface operations extends apiOperations, platformOperations {}
+export interface paths extends apiV2Paths, apiV1Paths, platformPaths {}
+export interface operations extends apiV2Operations, apiV1Operations, platformOperations {}
export interface components {
- schemas: apiComponents['schemas'] & platformComponents['schemas']
- responses: apiComponents['responses'] & platformComponents['responses']
- parameters: apiComponents['parameters'] & platformComponents['parameters']
- requestBodies: apiComponents['requestBodies'] & platformComponents['requestBodies']
- headers: apiComponents['headers'] & platformComponents['headers']
- pathItems: apiComponents['pathItems'] & platformComponents['pathItems']
+ schemas: apiV2Components['schemas'] & apiV1Components['schemas'] & platformComponents['schemas']
+ responses: apiV2Components['responses'] &
+ apiV1Components['responses'] &
+ platformComponents['responses']
+ parameters: apiV2Components['parameters'] &
+ apiV1Components['parameters'] &
+ platformComponents['parameters']
+ requestBodies: apiV2Components['requestBodies'] &
+ apiV1Components['requestBodies'] &
+ platformComponents['requestBodies']
+ headers: apiV2Components['headers'] & apiV1Components['headers'] & platformComponents['headers']
+ pathItems: apiV2Components['pathItems'] &
+ apiV1Components['pathItems'] &
+ platformComponents['pathItems']
}
-export type { platformComponents, apiComponents }
+export type { platformComponents, apiV1Components, apiV2Components }
diff --git a/packages/api-types/redocly.yaml b/packages/api-types/redocly.yaml
index 59023bf6afc39..1d34a034cef1a 100644
--- a/packages/api-types/redocly.yaml
+++ b/packages/api-types/redocly.yaml
@@ -1,9 +1,13 @@
apis:
- api:
+ api-v2:
+ root: http://localhost:8080/api/v2-json
+ x-openapi-ts:
+ output: ./types/api-v2.d.ts
+ api-v1:
root: http://localhost:8080/api/v1-json
x-openapi-ts:
- output: ./types/api.d.ts
+ output: ./types/api-v1.d.ts
platform:
root: http://localhost:8080/api/platform-json
x-openapi-ts:
- output: ./types/platform.d.ts
\ No newline at end of file
+ output: ./types/platform.d.ts
diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api-v1.d.ts
similarity index 100%
rename from packages/api-types/types/api.d.ts
rename to packages/api-types/types/api-v1.d.ts
diff --git a/packages/api-types/types/api-v2.d.ts b/packages/api-types/types/api-v2.d.ts
new file mode 100644
index 0000000000000..0824bc203aad8
--- /dev/null
+++ b/packages/api-types/types/api-v2.d.ts
@@ -0,0 +1,12062 @@
+/**
+ * This file was auto-generated by openapi-typescript.
+ * Do not make direct changes to the file.
+ */
+
+export interface paths {
+ '/v1/webhooks/events': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Publish event
+ * @description Ingests and schedules a new webhook event to be published out to all subscribed endpoints.
+ *
+ * In case of non-successful response status codes, early termination, networking issues,
+ * requests to this endpoint should be retried until it succeeds, otherwise there is a risk of
+ * loosing events.
+ *
+ * `meta.idempotency_key` is used to ensure idempotency when retrying the requests and so it
+ * must always be provided.
+ */
+ post: operations['postV1WebhooksEvents']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/integrations/github/connections': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List GitHub connections of an organization
+ * @description Returns a cursor-paginated list of the GitHub connections of the organization's projects.
+ *
+ * Use `page[after]` and `page[before]` to navigate pages and `page[size]` to control the page size.
+ * Paging walks the organization projects, so a page holds at most `page[size]` connections and can hold fewer (or none) when some of its projects are not connected.
+ * Follow `links.next` until it is `null` rather than stopping on a short page.
+ *
+ * Use `filter[project_ref]` to narrow the list down to a single project.
+ */
+ get: operations['v2-list-organization-github-connections']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/members': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List members of an organization
+ * @description Returns a cursor-paginated list of organization members including their roles and project-scoped permissions.
+ */
+ get: operations['v2-list-organization-members']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/members/{user_id}/roles': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ /**
+ * Assign or change an organization member role
+ * @description Assigns an org-wide role when projects is omitted, or creates a project-scoped assignment when projects is provided. Uses an org-level role template id from GET /v2/organizations/{slug}/roles. Stale role assignments are automatically cleaned up: if a role no longer has any projects, it is deleted; overlapping project assignments in other roles are automatically removed to avoid duplication.
+ */
+ patch: operations['v2-assign-organization-member-role']
+ trace?: never
+ }
+ '/v2/organizations/{slug}/members/invitations': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Creates organization invitations
+ * @description Creates member invitations for an organization. Each invitation can have different role and project scope settings.
+ */
+ post: operations['v2-create-organization-invitations']
+ /**
+ * Deletes organization invitations by email
+ * @description Bulk delete member invitations for an organization by email address.
+ */
+ delete: operations['v2-delete-organization-invitations']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/projects': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List projects of an organization
+ * @description Returns a cursor-paginated list of projects for the specified organization, including their databases.
+ *
+ * Use `page[after]` and `page[before]` to navigate pages and `page[size]` to control the number of projects returned per page.
+ */
+ get: operations['v2-list-organization-projects']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/roles': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List roles of an organization
+ * @description Returns a list of org-level roles for the organization.
+ */
+ get: operations['v2-list-organization-roles']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/webhooks/deliveries/{id}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Get delivery
+ * @description Get details of a specific delivery attempt.
+ */
+ get: operations['allV2OrganizationsBySlugWebhooks']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/webhooks/deliveries/{id}/retry': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Retry delivery
+ * @description Retry delivering the same event again.
+ *
+ * Automatic retries are not applicable to manual retries - if the delivery fails, there won't be any automatic retries attempted.
+ *
+ * This endpoint is heavy rate-limited to allow for 10 request within 60 seconds.
+ */
+ post: operations['allV2OrganizationsBySlugWebhooks']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/webhooks/endpoints': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List endpoints
+ * @description List all Webhook endpoints based on a project's ref or an organization's slug.
+ */
+ get: operations['allV2OrganizationsBySlugWebhooks']
+ put?: never
+ /**
+ * Create endpoint
+ * @description Create new endpoint configuration to subscribe to specific webhook events.
+ */
+ post: operations['allV2OrganizationsBySlugWebhooks']
+ /**
+ * Delete all endpoints
+ * @description Delete all endpoints including all events and deliveries.
+ *
+ * Any in-flight webhooks will result in a no-op.
+ */
+ delete: operations['allV2OrganizationsBySlugWebhooks']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/webhooks/endpoints/{id}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Get endpoint
+ * @description Get details of a specific endpoint.
+ */
+ get: operations['allV2OrganizationsBySlugWebhooks']
+ put?: never
+ post?: never
+ /**
+ * Delete endpoint
+ * @description Delete the endpoint including all events and deliveries
+ *
+ * Any in-flight webhooks will result in a no-op.
+ */
+ delete: operations['allV2OrganizationsBySlugWebhooks']
+ options?: never
+ head?: never
+ /**
+ * Update endpoint
+ * @description Update endpoint's configuration.
+ */
+ patch: operations['allV2OrganizationsBySlugWebhooks']
+ trace?: never
+ }
+ '/v2/organizations/{slug}/webhooks/endpoints/{id}/deliveries': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List deliveries
+ * @description List all deliveries for a specific endpoint in descending order (newest first).
+ *
+ * Deliveries which has expired are no longer available and will not be listed.
+ */
+ get: operations['allV2OrganizationsBySlugWebhooks']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/organizations/{slug}/webhooks/endpoints/{id}/test': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Send test event
+ * @description Ingests and schedules a test webhook event to be published out this endpoints.
+ *
+ * Which event type to use can be specified in the request body, otherwise
+ * it will use any matching type the endpoint is listening for.
+ *
+ * The event will contain `is_test: true` in it's payload.
+ *
+ * This endpoint is heavy rate-limited to allow for 10 request within 60 seconds.
+ */
+ post: operations['allV2OrganizationsBySlugWebhooks']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/analytics/log-drains': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /** List project log drains */
+ get: operations['v2-list-log-drains']
+ put?: never
+ /** Create a log drain for a project */
+ post: operations['v2-create-log-drain']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/analytics/log-drains/{id}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ /** Update a project log drain */
+ put: operations['v2-update-log-drain']
+ post?: never
+ /** Delete a project log drain */
+ delete: operations['v2-delete-log-drain']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/config': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * [Alpha] Get a project's service configuration
+ * @description Returns the project's database, pooler, Auth, Data API, Realtime and Storage configuration — the same configuration a branch inherits from its base project. Each is the effective config, so a setting the project has never overridden is reported at its platform default rather than as null. Auth secrets are returned as an HMAC of their value. `storage` is read live from the storage service; the rest come from this platform's own records.
+ */
+ get: operations['v2-get-project-config']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/private-link/associations': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /** List AWS accounts attached to the project PrivateLink share */
+ get: operations['v2-list-private-link-associations']
+ put?: never
+ /**
+ * Add an AWS account to the project PrivateLink share
+ * @description Adds an AWS account to the project's PrivateLink configuration and schedules the AWS resources to be created.
+ */
+ post: operations['v2-create-private-link-association']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/private-link/associations/aws-account/{aws_account_id}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ post?: never
+ /**
+ * Remove an AWS account from the project PrivateLink share
+ * @description Removes an AWS account from the project's PrivateLink configuration (targeting the primary database). Cleans up the associated AWS resources.
+ */
+ delete: operations['v2-delete-private-link-association']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/private-link/associations/aws-account/{aws_account_id}/database/{database_identifier}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ post?: never
+ /**
+ * Remove an AWS account from a specific database PrivateLink share
+ * @description Removes an AWS account from the project's PrivateLink configuration for the given read replica. Cleans up the associated AWS resources.
+ */
+ delete: operations['v2-delete-private-link-association-for-database']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/transfers': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /** Transfers a project to a different organization */
+ post: operations['v2-transfer-a-project']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/transfers/previews': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /** Previews transferring a project to a different organizations, shows eligibility and impact */
+ post: operations['v2-preview-a-project-transfer']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/webhooks/deliveries/{id}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Get delivery
+ * @description Get details of a specific delivery attempt.
+ */
+ get: operations['allV2ProjectsByRefWebhooks']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/webhooks/deliveries/{id}/retry': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Retry delivery
+ * @description Retry delivering the same event again.
+ *
+ * Automatic retries are not applicable to manual retries - if the delivery fails, there won't be any automatic retries attempted.
+ *
+ * This endpoint is heavy rate-limited to allow for 10 request within 60 seconds.
+ */
+ post: operations['allV2ProjectsByRefWebhooks']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/webhooks/endpoints': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List endpoints
+ * @description List all Webhook endpoints based on a project's ref or an organization's slug.
+ */
+ get: operations['allV2ProjectsByRefWebhooks']
+ put?: never
+ /**
+ * Create endpoint
+ * @description Create new endpoint configuration to subscribe to specific webhook events.
+ */
+ post: operations['allV2ProjectsByRefWebhooks']
+ /**
+ * Delete all endpoints
+ * @description Delete all endpoints including all events and deliveries.
+ *
+ * Any in-flight webhooks will result in a no-op.
+ */
+ delete: operations['allV2ProjectsByRefWebhooks']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/webhooks/endpoints/{id}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * Get endpoint
+ * @description Get details of a specific endpoint.
+ */
+ get: operations['allV2ProjectsByRefWebhooks']
+ put?: never
+ post?: never
+ /**
+ * Delete endpoint
+ * @description Delete the endpoint including all events and deliveries
+ *
+ * Any in-flight webhooks will result in a no-op.
+ */
+ delete: operations['allV2ProjectsByRefWebhooks']
+ options?: never
+ head?: never
+ /**
+ * Update endpoint
+ * @description Update endpoint's configuration.
+ */
+ patch: operations['allV2ProjectsByRefWebhooks']
+ trace?: never
+ }
+ '/v2/projects/{ref}/webhooks/endpoints/{id}/deliveries': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * List deliveries
+ * @description List all deliveries for a specific endpoint in descending order (newest first).
+ *
+ * Deliveries which has expired are no longer available and will not be listed.
+ */
+ get: operations['allV2ProjectsByRefWebhooks']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/webhooks/endpoints/{id}/test': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * Send test event
+ * @description Ingests and schedules a test webhook event to be published out this endpoints.
+ *
+ * Which event type to use can be specified in the request body, otherwise
+ * it will use any matching type the endpoint is listening for.
+ *
+ * The event will contain `is_test: true` in it's payload.
+ *
+ * This endpoint is heavy rate-limited to allow for 10 request within 60 seconds.
+ */
+ post: operations['allV2ProjectsByRefWebhooks']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/workers': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * [Alpha] List all workers
+ * @description Returns all workers you've previously deployed to the specified project.
+ */
+ get: operations['v2-list-all-workers']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/workers/{name}': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ /**
+ * [Alpha] Retrieve a worker
+ * @description Returns a worker along with its instance tally. Poll this after a deploy until `build_state` leaves `building`.
+ */
+ get: operations['v2-get-a-worker']
+ put?: never
+ post?: never
+ /**
+ * [Alpha] Delete a worker
+ * @description Tombstones the worker. Its instances and image are torn down asynchronously.
+ */
+ delete: operations['v2-delete-a-worker']
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/workers/{name}/deploy': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * [Alpha] Deploy a worker
+ * @description Creates the worker if it does not exist, building from a context staged through the uploads endpoint. The build runs asynchronously: this answers 202 and the worker reaches `build_state` `active` or `failed` later.
+ */
+ post: operations['v2-deploy-a-worker']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+ '/v2/projects/{ref}/workers/{name}/uploads': {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ get?: never
+ put?: never
+ /**
+ * [Alpha] Mint a presigned slot for a build-context upload
+ * @description PUT the `.tar.gz` build context to the returned `url` before `expires_at`, then deploy with the upload id as `context_upload_id`. The bytes go straight to storage — no management API request carries them.
+ */
+ post: operations['v2-create-worker-upload']
+ delete?: never
+ options?: never
+ head?: never
+ patch?: never
+ trace?: never
+ }
+}
+export type webhooks = Record
+export interface components {
+ schemas: {
+ APIErrorObject: {
+ code: string
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ message: string
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ CreateLogDrainRequestOpenApi: {
+ data: {
+ attributes: {
+ /** @enum {string} */
+ backend_type:
+ | 'postgres'
+ | 'bigquery'
+ | 'clickhouse'
+ | 'webhook'
+ | 'datadog'
+ | 'loki'
+ | 'sentry'
+ | 's3'
+ | 'axiom'
+ | 'last9'
+ | 'otlp'
+ | 'syslog'
+ config:
+ | {
+ hostname?: string
+ password?: string | null
+ port?: number | null
+ schema?: string
+ url?: string | null
+ username?: string | null
+ }
+ | {
+ gzip?: boolean
+ headers?: {
+ [key: string]: string
+ }
+ /** @enum {string} */
+ http?: 'http1' | 'http2'
+ url?: string
+ }
+ | {
+ dataset_id?: string
+ project_id?: string
+ }
+ | {
+ api_key?: string
+ region?: string
+ }
+ | {
+ headers?: {
+ [key: string]: string
+ }
+ password?: string | null
+ url?: string
+ username?: string | null
+ }
+ | {
+ dsn?: string
+ }
+ | {
+ api_token?: string
+ dataset_name?: string
+ domain?: string
+ }
+ | {
+ ca_cert?: string
+ cipher_key?: string
+ client_cert?: string
+ client_key?: string
+ host?: string
+ port?: number
+ structured_data?: string
+ /** @default false */
+ tls?: boolean
+ }
+ description?: string
+ name: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'log_drain'
+ }
+ }
+ ErrorResponseBody: {
+ error: components['schemas']['ErrorResponseBodyAPIErrorObject']
+ }
+ ErrorResponseBodyAPIErrorObject: {
+ code: string
+ description?: string
+ id?: string
+ issues?: components['schemas']['ErrorResponseBodyAPIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ message: string
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ ListLogDrainsResponse: {
+ data: {
+ attributes: {
+ /** @enum {string} */
+ backend_type:
+ | 'postgres'
+ | 'bigquery'
+ | 'clickhouse'
+ | 'webhook'
+ | 'datadog'
+ | 'loki'
+ | 'sentry'
+ | 's3'
+ | 'axiom'
+ | 'last9'
+ | 'otlp'
+ | 'syslog'
+ config:
+ | {
+ hostname?: string
+ password?: string | null
+ port?: number | null
+ schema?: string
+ url?: string | null
+ username?: string | null
+ }
+ | {
+ gzip?: boolean
+ headers?: {
+ [key: string]: string
+ }
+ /** @enum {string} */
+ http?: 'http1' | 'http2'
+ url?: string
+ }
+ | {
+ dataset_id?: string
+ project_id?: string
+ }
+ | {
+ api_key?: string
+ region?: string
+ }
+ | {
+ headers?: {
+ [key: string]: string
+ }
+ password?: string | null
+ url?: string
+ username?: string | null
+ }
+ | {
+ dsn?: string
+ }
+ | {
+ api_token?: string
+ dataset_name?: string
+ domain?: string
+ }
+ | {
+ ca_cert?: string
+ cipher_key?: string
+ client_cert?: string
+ client_key?: string
+ host?: string
+ port?: number
+ structured_data?: string
+ /** @default false */
+ tls?: boolean
+ }
+ description?: string
+ name: string
+ }
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'log_drain'
+ }[]
+ }
+ LogDrainResponse: {
+ data: {
+ attributes: {
+ /** @enum {string} */
+ backend_type:
+ | 'postgres'
+ | 'bigquery'
+ | 'clickhouse'
+ | 'webhook'
+ | 'datadog'
+ | 'loki'
+ | 'sentry'
+ | 's3'
+ | 'axiom'
+ | 'last9'
+ | 'otlp'
+ | 'syslog'
+ config:
+ | {
+ hostname?: string
+ password?: string | null
+ port?: number | null
+ schema?: string
+ url?: string | null
+ username?: string | null
+ }
+ | {
+ gzip?: boolean
+ headers?: {
+ [key: string]: string
+ }
+ /** @enum {string} */
+ http?: 'http1' | 'http2'
+ url?: string
+ }
+ | {
+ dataset_id?: string
+ project_id?: string
+ }
+ | {
+ api_key?: string
+ region?: string
+ }
+ | {
+ headers?: {
+ [key: string]: string
+ }
+ password?: string | null
+ url?: string
+ username?: string | null
+ }
+ | {
+ dsn?: string
+ }
+ | {
+ api_token?: string
+ dataset_name?: string
+ domain?: string
+ }
+ | {
+ ca_cert?: string
+ cipher_key?: string
+ client_cert?: string
+ client_key?: string
+ host?: string
+ port?: number
+ structured_data?: string
+ /** @default false */
+ tls?: boolean
+ }
+ description?: string
+ name: string
+ }
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'log_drain'
+ }
+ }
+ OrganizationMemberRoleResponse: {
+ data: {
+ attributes: {
+ /**
+ * @description Role name. For project-scoped assignments this is the base role name.
+ * @example developer
+ */
+ name: string
+ /** @description Project refs this role is scoped to. Empty array for org-level roles. */
+ projects: {
+ name: string
+ ref: string
+ }[]
+ /**
+ * @description Whether this role applies org-wide or is scoped to specific projects for the user.
+ * @enum {string}
+ */
+ scope: 'organization' | 'project'
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_member_role'
+ }
+ }
+ UpdateLogDrainRequestOpenApi: {
+ data: {
+ attributes: {
+ /** @enum {string} */
+ backend_type:
+ | 'postgres'
+ | 'bigquery'
+ | 'clickhouse'
+ | 'webhook'
+ | 'datadog'
+ | 'loki'
+ | 'sentry'
+ | 's3'
+ | 'axiom'
+ | 'last9'
+ | 'otlp'
+ | 'syslog'
+ config?:
+ | {
+ hostname?: string
+ password?: string | null
+ port?: number | null
+ schema?: string
+ url?: string | null
+ username?: string | null
+ }
+ | {
+ gzip?: boolean
+ headers?: {
+ [key: string]: string
+ }
+ /** @enum {string} */
+ http?: 'http1' | 'http2'
+ url?: string
+ }
+ | {
+ dataset_id?: string
+ project_id?: string
+ }
+ | {
+ api_key?: string
+ region?: string
+ }
+ | {
+ headers?: {
+ [key: string]: string
+ }
+ password?: string | null
+ url?: string
+ username?: string | null
+ }
+ | {
+ dsn?: string
+ }
+ | {
+ api_token?: string
+ dataset_name?: string
+ domain?: string
+ }
+ | {
+ ca_cert?: string
+ cipher_key?: string
+ client_cert?: string
+ client_key?: string
+ host?: string
+ port?: number
+ structured_data?: string
+ /** @default false */
+ tls?: boolean
+ }
+ description?: string
+ name?: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'log_drain'
+ }
+ }
+ V2AssignOrganizationMemberRoleRequest: {
+ data: {
+ attributes: {
+ /** @description The projects to assign a project-scoped role for. If omitted, assigns an org-wide role. */
+ projects?: {
+ /**
+ * @description Project ref
+ * @example abcjuqabhgwjjutfvtpa
+ */
+ ref: string
+ }[]
+ /**
+ * @description Role name to assign. Must be one of: owner, administrator, developer, read-only. Must be on a Team or Enterprise plan to use the read-only role.
+ * @example developer
+ * @enum {string}
+ */
+ role: 'owner' | 'administrator' | 'developer' | 'read-only'
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_member_role'
+ }
+ }
+ V2CreateInvitationsRequest: {
+ data: {
+ attributes: {
+ /** Format: email */
+ email: string
+ /** @description The projects to limit a user to. If omitted, user will have org-wide access with the provided role. */
+ projects?: {
+ /**
+ * @description Project ref
+ * @example abcjuqabhgwjjutfvtpa
+ */
+ ref: string
+ }[]
+ require_sso?: boolean
+ /**
+ * @description Role name to assign. Must be on a Team or Enterprise plan to use the read-only role.
+ * @example developer
+ * @enum {string}
+ */
+ role: 'owner' | 'administrator' | 'developer' | 'read-only'
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_invitation'
+ }[]
+ }
+ V2CreateInvitationsResponse: {
+ data: {
+ attributes: {
+ /** Format: email */
+ email: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_invitation'
+ }[]
+ error?: {
+ code: string
+ description?: string
+ id?: string
+ issues?: {
+ code: string
+ description?: string
+ id?: string
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ message: string
+ meta: {
+ /** Format: email */
+ email: string
+ }
+ }[]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ message: string
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ }
+ V2CreatePrivateLinkAssociationRequest: {
+ data: {
+ attributes: {
+ /** @description Optional human-readable name for the AWS account. */
+ account_name?: string
+ /** @description The AWS account ID to add to the project PrivateLink share. */
+ aws_account_id: string
+ /** @description Identifier of the read replica this PrivateLink share should target. Omit to target the primary database. */
+ database_identifier?: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'private_link_association'
+ }
+ }
+ V2DeleteInvitationsRequest: {
+ data: {
+ attributes: {
+ /** Format: email */
+ email: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_invitation'
+ }[]
+ }
+ V2DeleteInvitationsResponse: {
+ data: {
+ attributes: {
+ /** Format: email */
+ email: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_invitation'
+ }[]
+ }
+ V2DeployWorkerRequest: {
+ data: {
+ attributes: {
+ /** @description Id of a build context staged through the uploads endpoint. Required unless `runtime` is set. */
+ context_upload_id?: string
+ spec: {
+ backend?: string
+ /** @example public */
+ exposure: string
+ /** @example 1 */
+ instances: number
+ /** @example node */
+ runtime?: string
+ /** @example 2gb-1vcpu */
+ size: string
+ }
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project_worker'
+ }
+ }
+ V2ListGitHubConnectionsResponse: {
+ data: {
+ attributes: {
+ /** @description Maximum number of preview branches */
+ branch_limit: number
+ /** @description When the connection was created */
+ inserted_at: string
+ /** @description GitHub App installation id */
+ installation_id: number
+ /** @description Whether a preview branch is created for every pull request */
+ new_branch_per_pr: boolean
+ /** @description The connected Supabase project */
+ project: {
+ id: number
+ name: string
+ /**
+ * @description Project ref
+ * @example abcdefghijklmnopqrst
+ */
+ ref: string
+ }
+ /** @description The connected GitHub repository */
+ repository: {
+ id: number
+ name: string
+ }
+ /** @description Whether branches are only created for changes under `supabase/` */
+ supabase_changes_only: boolean
+ /** @description When the connection was last updated */
+ updated_at: string
+ /** @description The user who created the connection, if still known */
+ user: {
+ id: number
+ primary_email: string | null
+ username: string
+ } | null
+ /** @description Directory within the repository the project lives in */
+ workdir: string
+ }
+ /**
+ * @description Connection id.
+ * @example 7
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'github_connection'
+ }[]
+ links: {
+ /**
+ * @description URL path to the first page if available.
+ * @example /v2/organizations/my-org/integrations/github/connections?page[size]=10
+ */
+ first?: string | null
+ /**
+ * @description URL path to the last page if available.
+ * @example /v2/organizations/my-org/integrations/github/connections?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295
+ */
+ last?: string | null
+ /**
+ * @description URL path to the next page.
+ * @example /v2/organizations/my-org/integrations/github/connections?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4
+ */
+ next: string | null
+ /**
+ * @description URL path to the previous page.
+ * @example /v2/organizations/my-org/integrations/github/connections?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7
+ */
+ prev: string | null
+ }
+ }
+ V2ListMembersResponse: {
+ data: {
+ attributes: {
+ /** @description Member's avatar URL */
+ avatar_url: string | null
+ /** @description Whether this member is a Single Sign-On user */
+ is_sso_user: boolean
+ /** @description Whether Multi-Factor Authentication is enabled for this member */
+ mfa_enabled: boolean
+ /** @description Member's primary email */
+ primary_email: string | null
+ /** @description Roles assigned to this member. Includes both org-level and project-scoped roles. */
+ roles: {
+ /**
+ * @description Role name. For project-scoped roles this is the base role name.
+ * @example developer
+ */
+ name: string
+ /** @description Project refs this role is scoped to. Empty array for org-level roles. */
+ projects: {
+ name: string
+ ref: string
+ }[]
+ /**
+ * @description Whether this role applies org-wide or is scoped to specific projects for the user.
+ * @enum {string}
+ */
+ scope: 'organization' | 'project'
+ }[]
+ /** @description Member's username */
+ username: string | null
+ }
+ /** Format: uuid */
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_member'
+ }[]
+ links: {
+ /**
+ * @description URL path to the first page if available.
+ * @example /v2/organizations/my-org/members?page[size]=10
+ */
+ first?: string | null
+ /**
+ * @description URL path to the last page if available.
+ * @example /v2/organizations/my-org/members?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295
+ */
+ last?: string | null
+ /**
+ * @description URL path to the next page.
+ * @example /v2/organizations/my-org/members?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4
+ */
+ next: string | null
+ /**
+ * @description URL path to the previous page.
+ * @example /v2/organizations/my-org/members?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7
+ */
+ prev: string | null
+ }
+ }
+ V2ListPrivateLinkAssociationsResponse: {
+ data: {
+ attributes: {
+ /** @description Human-readable name for the AWS account. */
+ account_name?: string
+ /** @description The AWS account ID this PrivateLink share is associated with. */
+ aws_account_id: string
+ /** @description Identifier of the database this PrivateLink share targets - the project ref for the primary, or the read replica identifier. */
+ database_identifier: string
+ /**
+ * @description Whether this PrivateLink share targets the primary database or a read replica.
+ * @enum {string}
+ */
+ database_type: 'PRIMARY' | 'READ_REPLICA'
+ /** @description ARN of the AWS VPC Lattice resource configuration backing this PrivateLink share. */
+ resource_access_manager_resource_config_arn?: string
+ /** @description ID of the AWS VPC Lattice resource configuration backing this PrivateLink share. */
+ resource_access_manager_resource_config_id?: string
+ /** @description ARN of the AWS Resource Access Manager resource share for this association. */
+ resource_access_manager_share_arn?: string
+ /**
+ * Format: date-time
+ * @description The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.
+ */
+ shared_at: string | null
+ /**
+ * @description
+ * - `CREATING`: The PrivateLink resources and the Association are in the process of being created. The PrivateLink Share cannot be accepted yet.
+ * - `READY`: The PrivateLink resources have been created and the PrivateLink Share can be accepted for the duration of 12h after sharing. See `shared_at`.
+ * - `ASSOCIATION_REQUEST_EXPIRED`: The PrivateLink Share has not been accepted within the 12h time limit. This association can now be deleted.
+ * - `ASSOCIATION_ACCEPTED`: The PrivateLink Share was successfully accepted.
+ * - `CREATION_FAILED`: The PrivateLink resources failed to create. This likely means something went wrong on Supabase's and and support should be contacted.
+ * - `DELETING`: The PrivateLink resources and the Association are in the process of being deleted. The PrivateLink Share cannot be accepted yet.
+ *
+ * @enum {string}
+ */
+ status:
+ | 'CREATING'
+ | 'READY'
+ | 'ASSOCIATION_REQUEST_EXPIRED'
+ | 'ASSOCIATION_ACCEPTED'
+ | 'CREATION_FAILED'
+ | 'DELETING'
+ }
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'private_link_association'
+ }[]
+ }
+ V2ListProjectsResponse: {
+ data: {
+ attributes: {
+ /** @description Cloud provider hosting the project */
+ cloud_provider: string
+ /** @description The project's databases including compute and disk attributes. */
+ databases: {
+ cloud_provider: string
+ disk_last_modified_at?: string
+ disk_throughput_mbps?: number
+ /** @enum {string} */
+ disk_type?: 'gp3' | 'io2'
+ disk_volume_size_gb?: number
+ identifier: string
+ /** @enum {string} */
+ infra_compute_size?:
+ | 'pico'
+ | 'nano'
+ | 'micro'
+ | 'small'
+ | 'medium'
+ | 'large'
+ | 'xlarge'
+ | '2xlarge'
+ | '4xlarge'
+ | '8xlarge'
+ | '12xlarge'
+ | '16xlarge'
+ | '24xlarge'
+ | '24xlarge_optimized_memory'
+ | '24xlarge_optimized_cpu'
+ | '24xlarge_high_memory'
+ | '48xlarge'
+ | '48xlarge_optimized_memory'
+ | '48xlarge_optimized_cpu'
+ | '48xlarge_high_memory'
+ region: string | null
+ /** @enum {string} */
+ status:
+ | 'ACTIVE_HEALTHY'
+ | 'ACTIVE_UNHEALTHY'
+ | 'COMING_UP'
+ | 'GOING_DOWN'
+ | 'INIT_FAILED'
+ | 'REMOVED'
+ | 'RESTORING'
+ | 'UNKNOWN'
+ | 'INIT_READ_REPLICA'
+ | 'INIT_READ_REPLICA_FAILED'
+ | 'RESTARTING'
+ | 'RESIZING'
+ /** @enum {string} */
+ type: 'PRIMARY' | 'READ_REPLICA'
+ }[]
+ /** @description When the project was created */
+ inserted_at: string
+ /** @description Project name */
+ name: string
+ /** @description Region the project is hosted in */
+ region: string
+ /**
+ * @description Project status
+ * @enum {string}
+ */
+ status:
+ | 'INACTIVE'
+ | 'ACTIVE_HEALTHY'
+ | 'ACTIVE_UNHEALTHY'
+ | 'COMING_UP'
+ | 'UNKNOWN'
+ | 'GOING_DOWN'
+ | 'INIT_FAILED'
+ | 'REMOVED'
+ | 'RESTORING'
+ | 'UPGRADING'
+ | 'PAUSING'
+ | 'RESTORE_FAILED'
+ | 'RESTARTING'
+ | 'PAUSE_FAILED'
+ | 'RESIZING'
+ }
+ /**
+ * @description Project ref
+ * @example abcdefghijklmnopqrst
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project'
+ }[]
+ links: {
+ /**
+ * @description URL path to the first page if available.
+ * @example /v2/organizations/my-org/projects?page[size]=10
+ */
+ first?: string | null
+ /**
+ * @description URL path to the last page if available.
+ * @example /v2/organizations/my-org/projects?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295
+ */
+ last?: string | null
+ /**
+ * @description URL path to the next page.
+ * @example /v2/organizations/my-org/projects?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4
+ */
+ next: string | null
+ /**
+ * @description URL path to the previous page.
+ * @example /v2/organizations/my-org/projects?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7
+ */
+ prev: string | null
+ }
+ }
+ V2ListRolesResponse: {
+ data: {
+ attributes: {
+ /**
+ * @description Role name.
+ * @example developer
+ */
+ name: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'organization_role'
+ }[]
+ }
+ V2ListWorkersResponse: {
+ data: {
+ attributes: {
+ /** @enum {string} */
+ build_state: 'building' | 'active' | 'failed'
+ deleting?: boolean
+ image_version?: string
+ instances?: {
+ declared: number
+ live: number
+ ready: number
+ stale: number
+ }
+ instances_error?: string
+ secret_generation: string
+ spec: {
+ backend?: string
+ /** @example public */
+ exposure: string
+ /** @example 1 */
+ instances: number
+ /** @example node */
+ runtime?: string
+ /** @example 2gb-1vcpu */
+ size: string
+ }
+ state_reason?: string
+ }
+ /**
+ * @description Worker name.
+ * @example hello-world
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project_worker'
+ }[]
+ }
+ V2PreviewProjectTransferResponse: {
+ data: {
+ attributes: {
+ errors: {
+ key: string
+ message: string
+ }[]
+ info: {
+ key: string
+ message: string
+ }[]
+ valid: boolean
+ warnings: {
+ key: string
+ message: string
+ }[]
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project_transfer_result'
+ }
+ }
+ V2PrivateLinkAssociationResponse: {
+ data: {
+ attributes: {
+ /** @description Human-readable name for the AWS account. */
+ account_name?: string
+ /** @description The AWS account ID this PrivateLink share is associated with. */
+ aws_account_id: string
+ /** @description Identifier of the database this PrivateLink share targets - the project ref for the primary, or the read replica identifier. */
+ database_identifier: string
+ /**
+ * @description Whether this PrivateLink share targets the primary database or a read replica.
+ * @enum {string}
+ */
+ database_type: 'PRIMARY' | 'READ_REPLICA'
+ /** @description ARN of the AWS VPC Lattice resource configuration backing this PrivateLink share. */
+ resource_access_manager_resource_config_arn?: string
+ /** @description ID of the AWS VPC Lattice resource configuration backing this PrivateLink share. */
+ resource_access_manager_resource_config_id?: string
+ /** @description ARN of the AWS Resource Access Manager resource share for this association. */
+ resource_access_manager_share_arn?: string
+ /**
+ * Format: date-time
+ * @description The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.
+ */
+ shared_at: string | null
+ /**
+ * @description
+ * - `CREATING`: The PrivateLink resources and the Association are in the process of being created. The PrivateLink Share cannot be accepted yet.
+ * - `READY`: The PrivateLink resources have been created and the PrivateLink Share can be accepted for the duration of 12h after sharing. See `shared_at`.
+ * - `ASSOCIATION_REQUEST_EXPIRED`: The PrivateLink Share has not been accepted within the 12h time limit. This association can now be deleted.
+ * - `ASSOCIATION_ACCEPTED`: The PrivateLink Share was successfully accepted.
+ * - `CREATION_FAILED`: The PrivateLink resources failed to create. This likely means something went wrong on Supabase's and and support should be contacted.
+ * - `DELETING`: The PrivateLink resources and the Association are in the process of being deleted. The PrivateLink Share cannot be accepted yet.
+ *
+ * @enum {string}
+ */
+ status:
+ | 'CREATING'
+ | 'READY'
+ | 'ASSOCIATION_REQUEST_EXPIRED'
+ | 'ASSOCIATION_ACCEPTED'
+ | 'CREATION_FAILED'
+ | 'DELETING'
+ }
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'private_link_association'
+ }
+ }
+ V2ProjectConfigResponse: {
+ data: {
+ attributes: {
+ api: {
+ db_extra_search_path: string
+ /** @description If `null`, no pool size is written to the project's PostgREST config and PostgREST's own default applies. The platform does not pick a value here. */
+ db_pool: number | null
+ db_pool_acquisition_timeout: number
+ /** @description Schemas exposed through the Data API */
+ db_schema: string
+ max_rows: number
+ }
+ /** @description Effective Auth config, keyed by lowercased GoTrue setting name and resolved through the `gotrue_config` view, so a setting the project has never overridden is reported at its platform default. Secrets are returned as an HMAC of their value, never in plaintext. */
+ auth: {
+ [key: string]: unknown
+ }
+ database: {
+ network_restrictions: {
+ allowed_cidrs: {
+ address: string
+ /** @enum {string} */
+ type: 'v4' | 'v6'
+ }[]
+ applied_at?: string
+ /** @enum {string} */
+ entitlement: 'disallowed' | 'allowed'
+ /**
+ * @description Whether the allowlist below is applied to the project or only stored.
+ * @enum {string}
+ */
+ status: 'stored' | 'applied'
+ updated_at?: string
+ }
+ /** @description Postgres parameter overrides. Empty when the project runs entirely on defaults. */
+ postgres_settings: {
+ /** @description Default unit: s */
+ checkpoint_timeout?: string
+ cron_log_statement?: boolean
+ effective_cache_size?: string
+ hot_standby_feedback?: boolean
+ /** @description Default unit: ms */
+ log_autovacuum_min_duration?: string
+ log_checkpoints?: boolean
+ log_connections?: boolean
+ log_disconnections?: boolean
+ log_duration?: boolean
+ log_lock_waits?: boolean
+ log_recovery_conflict_waits?: boolean
+ log_replication_commands?: boolean
+ /** @description Default unit: ms */
+ log_startup_progress_interval?: string
+ log_temp_files?: string
+ logical_decoding_work_mem?: string
+ maintenance_work_mem?: string
+ max_connections?: number
+ max_locks_per_transaction?: number
+ max_logical_replication_workers?: number
+ max_parallel_maintenance_workers?: number
+ max_parallel_workers?: number
+ max_parallel_workers_per_gather?: number
+ max_replication_slots?: number
+ max_slot_wal_keep_size?: string
+ max_standby_archive_delay?: string
+ max_standby_streaming_delay?: string
+ max_sync_workers_per_subscription?: number
+ max_wal_senders?: number
+ max_wal_size?: string
+ max_worker_processes?: number
+ /** @enum {string} */
+ session_replication_role?: 'origin' | 'replica' | 'local'
+ shared_buffers?: string
+ /** @description Default unit: ms */
+ statement_timeout?: string
+ track_activity_query_size?: string
+ track_commit_timestamp?: boolean
+ wal_keep_size?: string
+ /** @description Default unit: ms */
+ wal_sender_timeout?: string
+ work_mem?: string
+ }
+ /** @description Whether the database rejects plaintext connections */
+ ssl_enforced: boolean
+ }
+ pooler: {
+ /** @description Defaults to the pooler's size for the project's compute when not overridden. */
+ default_pool_size: number
+ ignore_startup_parameters: string
+ /** @description Defaults to the pooler's size for the project's compute when not overridden. */
+ max_client_conn: number
+ /** @enum {string} */
+ pool_mode: 'transaction' | 'session' | 'statement'
+ query_wait_timeout: number
+ reserve_pool_size: number
+ server_idle_timeout: number
+ server_lifetime: number
+ }
+ realtime: {
+ /** @description Defaults to Realtime's pool size for the project's compute when not overridden. */
+ connection_pool: number
+ max_bytes_per_second: number
+ max_channels_per_client: number
+ max_concurrent_users: number
+ max_events_per_second: number
+ max_joins_per_second: number
+ max_payload_size_in_kb: number
+ max_presence_events_per_second: number
+ /** @description If `null`, no override is stored and Realtime applies its own default. */
+ postgres_changes_pool: number | null
+ presence_enabled: boolean
+ private_only: boolean
+ suspend: boolean
+ }
+ /** @description Read from the storage service's admin API rather than the middleware DB, so unlike the rest of this resource it reflects the tenant's live config. */
+ storage: {
+ capabilities: {
+ iceberg_catalog: boolean
+ list_v2: boolean
+ }
+ database_pool_mode: string
+ features: {
+ iceberg_catalog: {
+ enabled: boolean
+ max_catalogs: number
+ max_namespaces: number
+ max_tables: number
+ }
+ image_transformation: {
+ enabled: boolean
+ }
+ purge_cache: {
+ enabled: boolean
+ }
+ s3_protocol: {
+ enabled: boolean
+ }
+ vector_buckets: {
+ enabled: boolean
+ max_buckets: number
+ max_indexes: number
+ }
+ }
+ /** Format: int64 */
+ file_size_limit: number
+ migration_version: string
+ /** @enum {string} */
+ upstream_target: 'main' | 'canary'
+ }
+ }
+ /** @description Project ref. */
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project_config'
+ }
+ }
+ V2TransferProjectBody: {
+ data: {
+ attributes: {
+ target_organization_slug: string
+ }
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project_transfer_input'
+ }
+ }
+ V2WorkerResponse: {
+ data: {
+ attributes: {
+ /** @enum {string} */
+ build_state: 'building' | 'active' | 'failed'
+ deleting?: boolean
+ image_version?: string
+ instances?: {
+ declared: number
+ live: number
+ ready: number
+ stale: number
+ }
+ instances_error?: string
+ secret_generation: string
+ spec: {
+ backend?: string
+ /** @example public */
+ exposure: string
+ /** @example 1 */
+ instances: number
+ /** @example node */
+ runtime?: string
+ /** @example 2gb-1vcpu */
+ size: string
+ }
+ state_reason?: string
+ }
+ /**
+ * @description Worker name.
+ * @example hello-world
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project_worker'
+ }
+ }
+ V2WorkerUploadResponse: {
+ data: {
+ attributes: {
+ /** @description When the slot stops accepting the upload. */
+ expires_at: string
+ /** @example PUT */
+ method: string
+ /** @description Presigned destination for the `.tar.gz` build context. */
+ url: string
+ }
+ /**
+ * @description Upload id to pass to the deploy endpoint as `context_upload_id`.
+ * @example cafe0000000000000000000000000000
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @enum {string}
+ */
+ type: 'project_worker_upload'
+ }
+ }
+ }
+ responses: never
+ parameters: never
+ requestBodies: never
+ headers: never
+ pathItems: never
+}
+export type $defs = Record
+export interface operations {
+ postV1WebhooksEvents: {
+ parameters: {
+ query?: never
+ header?: never
+ path?: never
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * @description Organization slug
+ * @example tsrqponmlkjihgfedcba
+ */
+ organization_slug: string
+ /** @description Extra data to pass to consumers. `organization_slug` and `project_ref` (if applicable) are always provided by default. */
+ payload?: {
+ [key: string]: unknown
+ }
+ /** @description Project's ref. If left unspecified or `null`, the event will published as organization-wide, only to organization-wide endpoints. */
+ project_ref?: string | null
+ /**
+ * Format: date-time
+ * @description Optional timestamp of event publication.
+ */
+ timestamp?: string
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | 'project.v1.paused'
+ | 'project.v1.created'
+ | 'project.v1.restored'
+ | 'project.v1.transferred'
+ | 'project.v1.removed'
+ | 'project.v1.restarted'
+ | 'project.v1.status.changed'
+ | 'project.v1.backup.started'
+ | 'project.v1.branch.created'
+ | 'project.v1.branch.updated'
+ | 'project.v1.branch.removed'
+ | 'organization.v1.member.invitation.created'
+ | 'organization.v1.member.invitation.canceled'
+ | 'organization.v1.member.added'
+ | 'organization.v1.member.removed'
+ | 'organization.v1.member.role.assigned'
+ | 'organization.v1.member.role.removed'
+ | 'organization.v1.member.role.updated'
+ | 'organization.v1.billing.plan.upgraded'
+ | 'organization.v1.billing.plan.downgraded'
+ | 'project.v1.branch.deleted'
+ }
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'event'
+ }
+ meta: {
+ /** @description Idempotency key. */
+ idempotency_key: string
+ }
+ }
+ }
+ }
+ responses: {
+ /** @description Events published */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'ingress'
+ }
+ }
+ }
+ }
+ /** @description PermissionDenied */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'internal_server_error.event.ingress_failed'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error: Failed to ingress the event'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description TemporarilyDisabled */
+ 503: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'service_unavailable.temporarily_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Service Unavailable: Temporarily disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ 'v2-list-organization-github-connections': {
+ parameters: {
+ query?: {
+ filter?: {
+ /**
+ * @description Project ref
+ * @example abcdefghijklmnopqrst
+ */
+ project_ref?: string
+ }
+ page?: {
+ /**
+ * @description Project ref
+ * @example abcdefghijklmnopqrst
+ */
+ after?: string
+ /**
+ * @description Project ref
+ * @example abcdefghijklmnopqrst
+ */
+ before?: string
+ size?: number
+ }
+ }
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2ListGitHubConnectionsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-list-organization-members': {
+ parameters: {
+ query?: {
+ filter?: {
+ /** Format: email */
+ primary_email?: string
+ username?: string
+ }
+ page?: {
+ /** Format: uuid */
+ after?: string
+ /** Format: uuid */
+ before?: string
+ size?: number
+ }
+ }
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2ListMembersResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-assign-organization-member-role': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ user_id: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['V2AssignOrganizationMemberRoleRequest']
+ }
+ }
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['OrganizationMemberRoleResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description This feature requires the Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to assign organization member role */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-create-organization-invitations': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['V2CreateInvitationsRequest']
+ }
+ }
+ responses: {
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2CreateInvitationsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description This feature requires the Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-delete-organization-invitations': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['V2DeleteInvitationsRequest']
+ }
+ }
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2DeleteInvitationsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description This feature requires the Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-list-organization-projects': {
+ parameters: {
+ query?: {
+ page?: {
+ after?: string
+ before?: string
+ size?: number
+ }
+ /** @description Case-insensitive substring match on the project name. */
+ search?: string
+ /** @description Sort order by creation time: `inserted_at` (oldest first) or `-inserted_at` (newest first). Defaults to `inserted_at`. */
+ sort?: 'inserted_at' | '-inserted_at'
+ }
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2ListProjectsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-list-organization-roles': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2ListRolesResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of a delivery (UUID v7). */
+ id: string
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Delivery details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of the attempt.
+ */
+ attempt_timestamp: string
+ event: {
+ /** @description Final data sent to the consumer. */
+ payload: {
+ /**
+ * @description Organization slug
+ * @example tsrqponmlkjihgfedcba
+ */
+ organization_slug: string
+ project_ref: string | null
+ } & {
+ [key: string]: unknown
+ }
+ /**
+ * Format: date-time
+ * @description Timestamp of event publication.
+ */
+ timestamp: string
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | 'project.v1.paused'
+ | 'project.v1.created'
+ | 'project.v1.restored'
+ | 'project.v1.transferred'
+ | 'project.v1.removed'
+ | 'project.v1.restarted'
+ | 'project.v1.status.changed'
+ | 'project.v1.backup.started'
+ | 'project.v1.branch.created'
+ | 'project.v1.branch.updated'
+ | 'project.v1.branch.removed'
+ | 'organization.v1.member.invitation.created'
+ | 'organization.v1.member.invitation.canceled'
+ | 'organization.v1.member.added'
+ | 'organization.v1.member.removed'
+ | 'organization.v1.member.role.assigned'
+ | 'organization.v1.member.role.removed'
+ | 'organization.v1.member.role.updated'
+ | 'organization.v1.billing.plan.upgraded'
+ | 'organization.v1.billing.plan.downgraded'
+ | 'project.v1.branch.deleted'
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of the event, which triggered the delivery (UUID v7).
+ */
+ event_id: string
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ response_body:
+ | (
+ | {
+ [key: string]: string
+ }
+ | string
+ )
+ | null
+ /** @description HTTP status code of the response, `0` if unavailable. */
+ response_code: number
+ /** @description HTTP headers of the response, `{}` if unavailable. */
+ response_headers: {
+ [key: string]: string
+ } | null
+ /**
+ * @description Status of the delivery attempt.
+ * @enum {string}
+ */
+ status: 'pending' | 'success' | 'failure' | 'skipped'
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'delivery'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description DeliveryNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.delivery'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Delivery not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of a delivery (UUID v7). */
+ id: string
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Delivery details */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'ingress'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description DeliveryNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.delivery'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Delivery not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: {
+ /** @description Up to how many records to return. */
+ 'page[limit]'?: string
+ /** @description Offset for offset-based pagination.
+ *
+ * Offset should be dividable by `page[limit]` without a reminder (`offset % limit === 0`), otherwise it will cause weird behavior when used on a frontend. */
+ 'page[offset]'?: string
+ }
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Collection of endpoints */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }[]
+ links: {
+ /**
+ * @description URL path to the first page if available.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=0
+ */
+ first?: string | null
+ /**
+ * @description URL path to the last page if available.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=30
+ */
+ last?: string | null
+ /**
+ * @description URL path to the next page.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=20
+ */
+ next: string | null
+ /**
+ * @description URL path to the previous page.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=0
+ */
+ prev: string | null
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description?: string | null
+ /**
+ * @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events.
+ * @default true
+ */
+ enabled?: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /** @description Secret key to use when signing. All events will be signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) specification. */
+ signing_secret: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ responses: {
+ /** @description Created endpoint */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Deleted endpoints */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }[]
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Endpoint details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Deleted endpoint details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description?: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled?: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types?: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /** @description Secret key to use when signing. All events will be signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) specification. */
+ signing_secret?: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url?: string
+ }
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ responses: {
+ /** @description Updated endpoint details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: {
+ /** @description Cursor in cursor-based pagination to return up to `page[size]` records after (exclusive) the entry specified by this query param. */
+ 'page[after]'?: string
+ /** @description Cursor in cursor-based pagination to return up to `page[size]` records before (exclusive) the entry specified by this query param. */
+ 'page[before]'?: string
+ /** @description Up to how many records to return. */
+ 'page[size]'?: string
+ }
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description List of deliveries */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of the attempt.
+ */
+ attempt_timestamp: string
+ /**
+ * Format: uuid
+ * @description Identifier of the event, which triggered the delivery (UUID v7).
+ */
+ event_id: string
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ response_body:
+ | (
+ | {
+ [key: string]: string
+ }
+ | string
+ )
+ | null
+ /** @description HTTP status code of the response, `0` if unavailable. */
+ response_code: number
+ /** @description HTTP headers of the response, `{}` if unavailable. */
+ response_headers: {
+ [key: string]: string
+ } | null
+ /**
+ * @description Status of the delivery attempt.
+ * @enum {string}
+ */
+ status: 'pending' | 'success' | 'failure' | 'skipped'
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'delivery'
+ }[]
+ links: {
+ /**
+ * @description URL path to the first page if available.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10
+ */
+ first?: string | null
+ /**
+ * @description URL path to the last page if available.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295
+ */
+ last?: string | null
+ /**
+ * @description URL path to the next page.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4
+ */
+ next: string | null
+ /**
+ * @description URL path to the previous page.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7
+ */
+ prev: string | null
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2OrganizationsBySlugWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Organization slug */
+ slug: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': {
+ data?: {
+ attributes: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | 'project.v1.paused'
+ | 'project.v1.created'
+ | 'project.v1.restored'
+ | 'project.v1.transferred'
+ | 'project.v1.removed'
+ | 'project.v1.restarted'
+ | 'project.v1.status.changed'
+ | 'project.v1.backup.started'
+ | 'project.v1.branch.created'
+ | 'project.v1.branch.updated'
+ | 'project.v1.branch.removed'
+ | 'organization.v1.member.invitation.created'
+ | 'organization.v1.member.invitation.canceled'
+ | 'organization.v1.member.added'
+ | 'organization.v1.member.removed'
+ | 'organization.v1.member.role.assigned'
+ | 'organization.v1.member.role.removed'
+ | 'organization.v1.member.role.updated'
+ | 'organization.v1.billing.plan.upgraded'
+ | 'organization.v1.billing.plan.downgraded'
+ | 'project.v1.branch.deleted'
+ }
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'event'
+ }
+ }
+ }
+ }
+ responses: {
+ /** @description Event published */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'ingress'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.endpoint.test.disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Endpoint is disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.endpoint.test.wrong_event_type'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Provided event type is not subscribed to by the endpoint'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ 'v2-list-log-drains': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ListLogDrainsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to fetch log drains */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-create-log-drain': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['CreateLogDrainRequestOpenApi']
+ }
+ }
+ responses: {
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['LogDrainResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description This feature requires the Pro, Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to create a log drain */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-update-log-drain': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Log drains identifier */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['UpdateLogDrainRequestOpenApi']
+ }
+ }
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['LogDrainResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to update log drain */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-delete-log-drain': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Log drains identifier */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 204: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to delete a log drain */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-get-project-config': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2ProjectConfigResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-list-private-link-associations': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2ListPrivateLinkAssociationsResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to retrieve AWS accounts for project */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-create-private-link-association': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['V2CreatePrivateLinkAssociationRequest']
+ }
+ }
+ responses: {
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2PrivateLinkAssociationResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description This feature requires the Team, or Enterprise organization plan. */
+ 402: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to add AWS account to PrivateLink share */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-delete-private-link-association': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description AWS account ID used in PrivateLink association */
+ aws_account_id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 204: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to remove AWS account from PrivateLink share */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-delete-private-link-association-for-database': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description AWS account ID used in PrivateLink association */
+ aws_account_id: string
+ /** @description Identifier of the read replica this PrivateLink association targets */
+ database_identifier: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 204: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Failed to remove AWS account from PrivateLink share */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-transfer-a-project': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['V2TransferProjectBody']
+ }
+ }
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-preview-a-project-transfer': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['V2TransferProjectBody']
+ }
+ }
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2PreviewProjectTransferResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of a delivery (UUID v7). */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Delivery details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of the attempt.
+ */
+ attempt_timestamp: string
+ event: {
+ /** @description Final data sent to the consumer. */
+ payload: {
+ /**
+ * @description Organization slug
+ * @example tsrqponmlkjihgfedcba
+ */
+ organization_slug: string
+ project_ref: string | null
+ } & {
+ [key: string]: unknown
+ }
+ /**
+ * Format: date-time
+ * @description Timestamp of event publication.
+ */
+ timestamp: string
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | 'project.v1.paused'
+ | 'project.v1.created'
+ | 'project.v1.restored'
+ | 'project.v1.transferred'
+ | 'project.v1.removed'
+ | 'project.v1.restarted'
+ | 'project.v1.status.changed'
+ | 'project.v1.backup.started'
+ | 'project.v1.branch.created'
+ | 'project.v1.branch.updated'
+ | 'project.v1.branch.removed'
+ | 'organization.v1.member.invitation.created'
+ | 'organization.v1.member.invitation.canceled'
+ | 'organization.v1.member.added'
+ | 'organization.v1.member.removed'
+ | 'organization.v1.member.role.assigned'
+ | 'organization.v1.member.role.removed'
+ | 'organization.v1.member.role.updated'
+ | 'organization.v1.billing.plan.upgraded'
+ | 'organization.v1.billing.plan.downgraded'
+ | 'project.v1.branch.deleted'
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of the event, which triggered the delivery (UUID v7).
+ */
+ event_id: string
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ response_body:
+ | (
+ | {
+ [key: string]: string
+ }
+ | string
+ )
+ | null
+ /** @description HTTP status code of the response, `0` if unavailable. */
+ response_code: number
+ /** @description HTTP headers of the response, `{}` if unavailable. */
+ response_headers: {
+ [key: string]: string
+ } | null
+ /**
+ * @description Status of the delivery attempt.
+ * @enum {string}
+ */
+ status: 'pending' | 'success' | 'failure' | 'skipped'
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'delivery'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description DeliveryNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.delivery'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Delivery not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of a delivery (UUID v7). */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Delivery details */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'ingress'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description DeliveryNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.delivery'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Delivery not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: {
+ /** @description Up to how many records to return. */
+ 'page[limit]'?: string
+ /** @description Offset for offset-based pagination.
+ *
+ * Offset should be dividable by `page[limit]` without a reminder (`offset % limit === 0`), otherwise it will cause weird behavior when used on a frontend. */
+ 'page[offset]'?: string
+ }
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Collection of endpoints */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }[]
+ links: {
+ /**
+ * @description URL path to the first page if available.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=0
+ */
+ first?: string | null
+ /**
+ * @description URL path to the last page if available.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=30
+ */
+ last?: string | null
+ /**
+ * @description URL path to the next page.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=20
+ */
+ next: string | null
+ /**
+ * @description URL path to the previous page.
+ * @example /v2/organization/slug/webhooks/endpoints?page[limit]=10&page[offset]=0
+ */
+ prev: string | null
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description?: string | null
+ /**
+ * @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events.
+ * @default true
+ */
+ enabled?: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /** @description Secret key to use when signing. All events will be signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) specification. */
+ signing_secret: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ responses: {
+ /** @description Created endpoint */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Deleted endpoints */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }[]
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Endpoint details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description Deleted endpoint details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description?: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled?: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types?: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /** @description Secret key to use when signing. All events will be signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) specification. */
+ signing_secret?: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url?: string
+ }
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ responses: {
+ /** @description Updated endpoint details */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of endpoint's creation.
+ */
+ created_at: string
+ /**
+ * Format: uuid
+ * @description ID of the user who created the endpoint.
+ */
+ created_by: string
+ /**
+ * @description Additional request headers to pass when performing HTTP request location defined by `url`. Both keys and values must be strings and a valid HTTP headers.
+ * @example {
+ * "Authorization": "Bearer example_token"
+ * }
+ */
+ custom_headers?: {
+ [key: string]: string
+ } | null
+ /** @description Optional description for the endpoint. */
+ description: string | null
+ /** @description Whether the endpoint is enabled or not - disabled endpoints won't emit any events. */
+ enabled: boolean
+ /**
+ * @description List of subscribed events for which to receive the webhook event.
+ * @example [
+ * {
+ * "type": "v1.project.paused"
+ * }
+ * ]
+ */
+ event_types: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | '*'
+ }[]
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * Format: uri
+ * @description Publicly available URL where to send the events, must use a domain and be resolvable to a non-reserved IP address.
+ * @example https://mydomain.com/path/to/handler
+ */
+ url: string
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of an endpoint (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'endpoint'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: {
+ /** @description Cursor in cursor-based pagination to return up to `page[size]` records after (exclusive) the entry specified by this query param. */
+ 'page[after]'?: string
+ /** @description Cursor in cursor-based pagination to return up to `page[size]` records before (exclusive) the entry specified by this query param. */
+ 'page[before]'?: string
+ /** @description Up to how many records to return. */
+ 'page[size]'?: string
+ }
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ /** @description List of deliveries */
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ attributes: {
+ /**
+ * Format: date-time
+ * @description Timestamp of the attempt.
+ */
+ attempt_timestamp: string
+ /**
+ * Format: uuid
+ * @description Identifier of the event, which triggered the delivery (UUID v7).
+ */
+ event_id: string
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ response_body:
+ | (
+ | {
+ [key: string]: string
+ }
+ | string
+ )
+ | null
+ /** @description HTTP status code of the response, `0` if unavailable. */
+ response_code: number
+ /** @description HTTP headers of the response, `{}` if unavailable. */
+ response_headers: {
+ [key: string]: string
+ } | null
+ /**
+ * @description Status of the delivery attempt.
+ * @enum {string}
+ */
+ status: 'pending' | 'success' | 'failure' | 'skipped'
+ }
+ /**
+ * Format: uuid
+ * @description Identifier of a delivery (UUID v7).
+ */
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'delivery'
+ }[]
+ links: {
+ /**
+ * @description URL path to the first page if available.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10
+ */
+ first?: string | null
+ /**
+ * @description URL path to the last page if available.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295
+ */
+ last?: string | null
+ /**
+ * @description URL path to the next page.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4
+ */
+ next: string | null
+ /**
+ * @description URL path to the previous page.
+ * @example /v2/organizations/slug/webhooks/endpoints/{id}/deliveries?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7
+ */
+ prev: string | null
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ allV2ProjectsByRefWebhooks: {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Identifier of an endpoint (UUID v7). */
+ id: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': {
+ data?: {
+ attributes: {
+ /**
+ * @description Webhook event type.
+ * @enum {string}
+ */
+ type:
+ | 'v1.project.paused'
+ | 'v1.project.created'
+ | 'v1.project.restored'
+ | 'v1.project.transferred'
+ | 'v1.project.removed'
+ | 'v1.project.restarted'
+ | 'v1.project.status.changed'
+ | 'v1.project.backup.started'
+ | 'v1.project.branch.created'
+ | 'v1.project.branch.updated'
+ | 'v1.project.branch.removed'
+ | 'v1.organization.member.invitation.created'
+ | 'v1.organization.member.invitation.canceled'
+ | 'v1.organization.member.added'
+ | 'v1.organization.member.removed'
+ | 'v1.organization.member.role.assigned'
+ | 'v1.organization.member.role.removed'
+ | 'v1.organization.member.role.updated'
+ | 'v1.organization.billing.plan.upgraded'
+ | 'v1.organization.billing.plan.downgraded'
+ | 'project.v1.paused'
+ | 'project.v1.created'
+ | 'project.v1.restored'
+ | 'project.v1.transferred'
+ | 'project.v1.removed'
+ | 'project.v1.restarted'
+ | 'project.v1.status.changed'
+ | 'project.v1.backup.started'
+ | 'project.v1.branch.created'
+ | 'project.v1.branch.updated'
+ | 'project.v1.branch.removed'
+ | 'organization.v1.member.invitation.created'
+ | 'organization.v1.member.invitation.canceled'
+ | 'organization.v1.member.added'
+ | 'organization.v1.member.removed'
+ | 'organization.v1.member.role.assigned'
+ | 'organization.v1.member.role.removed'
+ | 'organization.v1.member.role.updated'
+ | 'organization.v1.billing.plan.upgraded'
+ | 'organization.v1.billing.plan.downgraded'
+ | 'project.v1.branch.deleted'
+ }
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'event'
+ }
+ }
+ }
+ }
+ responses: {
+ /** @description Event published */
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ data: {
+ id: string
+ /**
+ * @description Resource type.
+ * @constant
+ */
+ type: 'ingress'
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'bad_request.endpoint.test.disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Endpoint is disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.endpoint.test.wrong_event_type'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Provided event type is not subscribed to by the endpoint'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_slug'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid organization slug'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'bad_request.invalid_ref'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Bad Request: Invalid project ref'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericUnauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'unauthorized'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Unauthorized'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description Multiple error responses */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error:
+ | {
+ /** @constant */
+ code: 'forbidden.permission_denied'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Permission denied'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ | {
+ /** @constant */
+ code: 'forbidden.access_disabled'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Forbidden: Access disabled'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description EndpointNotFound */
+ 404: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'not_found.endpoint'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Not Found: Endpoint not found'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericRequestTimeout */
+ 408: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'request_timeout'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Request Timeout'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericTooManyRequests */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'too_many_requests'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Too Many Requests'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ /** @description GenericInternalServerError */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': {
+ error: {
+ /** @constant */
+ code: 'internal_server_error'
+ description?: string
+ id?: string
+ issues?: components['schemas']['APIErrorObject'][]
+ links?: {
+ [key: string]: {
+ describedby?: string
+ href: string
+ meta?: {
+ [key: string]: unknown
+ }
+ rel?: string
+ title?: string
+ type?: string
+ }
+ }
+ /** @constant */
+ message: 'Internal Server Error'
+ meta?: {
+ [key: string]: unknown
+ }
+ }
+ $defs: {
+ APIErrorObject: components['schemas']['APIErrorObject']
+ }
+ }
+ }
+ }
+ }
+ }
+ 'v2-list-all-workers': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2ListWorkersResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-get-a-worker': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ name: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 200: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2WorkerResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-delete-a-worker': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ name: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 204: {
+ headers: {
+ [name: string]: unknown
+ }
+ content?: never
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-deploy-a-worker': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ name: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['V2DeployWorkerRequest']
+ }
+ }
+ responses: {
+ 202: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2WorkerResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+ 'v2-create-worker-upload': {
+ parameters: {
+ query?: never
+ header?: never
+ path: {
+ name: string
+ /** @description Project ref */
+ ref: string
+ }
+ cookie?: never
+ }
+ requestBody?: never
+ responses: {
+ 201: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['V2WorkerUploadResponse']
+ }
+ }
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Forbidden action */
+ 403: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ /** @description Rate limit exceeded */
+ 429: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponseBody']
+ }
+ }
+ }
+ }
+}
diff --git a/packages/api-types/types/platform.d.ts b/packages/api-types/types/platform.d.ts
index 7e85290092779..5b5b673b49555 100644
--- a/packages/api-types/types/platform.d.ts
+++ b/packages/api-types/types/platform.d.ts
@@ -5890,6 +5890,8 @@ export interface components {
| 'vanity_subdomain_write'
| 'platform_webhooks_projects_read'
| 'platform_webhooks_projects_write'
+ | 'workers_read'
+ | 'workers_write'
)[]
}
CreatePlatformAppResponse: {
@@ -5942,6 +5944,7 @@ export interface components {
| 'm7g.medium'
| 'm8g.medium'
| 'm9g.medium'
+ | 'c6g.medium'
| 'm6g.large'
| 'm6a.large'
| 'm6i.large'
@@ -7125,6 +7128,8 @@ export interface components {
| 'vanity_subdomain_write'
| 'platform_webhooks_projects_read'
| 'platform_webhooks_projects_write'
+ | 'workers_read'
+ | 'workers_write'
)[]
project_refs?: string[]
}
@@ -7756,6 +7761,12 @@ export interface components {
* @enum {string}
*/
database_type: 'PRIMARY' | 'READ_REPLICA'
+ /** @description ARN of the AWS VPC Lattice resource configuration backing this PrivateLink share. */
+ resource_access_manager_resource_config_arn?: string
+ /** @description ID of the AWS VPC Lattice resource configuration backing this PrivateLink share. */
+ resource_access_manager_resource_config_id?: string
+ /** @description ARN of the AWS Resource Access Manager resource share for this association. */
+ resource_access_manager_share_arn?: string
/**
* Format: date-time
* @description The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.
@@ -12525,6 +12536,8 @@ export interface components {
| 'vanity_subdomain_write'
| 'platform_webhooks_projects_read'
| 'platform_webhooks_projects_write'
+ | 'workers_read'
+ | 'workers_write'
)[]
}
UpdatePlatformAppInstallationResponse: {
From 09894096e2e24e5369e5b7794da68b0d797abc00 Mon Sep 17 00:00:00 2001
From: Joshen Lim
Date: Thu, 13 Aug 2026 16:42:28 +0700
Subject: [PATCH 5/6] Add log scale support to query result chart (#49049)
## Context
Related to Explorer/Notebooks - Adds support for log scale in the charts
Prevents setting to log scale if y axis has yet to be selected, or if
the data set contains non positive values
## Summary by CodeRabbit
- **New Features**
- Added logarithmic Y-axis scaling for line and bar charts.
- Added logarithmic tick formatting and appropriate chart bounds.
- Added contextual guidance when logarithmic scaling is unavailable.
- **Bug Fixes**
- Automatically switches charts back to linear scaling when data
contains values that cannot support logarithmic scaling.
- Prevented unnecessary stacking for single-series area charts.
---
.../QueryCell/DisplaySettingsButton.tsx | 57 +++++++++++++++++--
.../Explorer/QueryCell/QueryResultChart.tsx | 14 ++++-
.../interfaces/Explorer/QueryCell/index.tsx | 1 +
.../src/Chart/charts/chart-bar.tsx | 3 +
.../src/Chart/charts/chart-line.tsx | 5 +-
5 files changed, 73 insertions(+), 7 deletions(-)
diff --git a/apps/studio/components/interfaces/Explorer/QueryCell/DisplaySettingsButton.tsx b/apps/studio/components/interfaces/Explorer/QueryCell/DisplaySettingsButton.tsx
index 96460ec03ec24..29a8ee384277d 100644
--- a/apps/studio/components/interfaces/Explorer/QueryCell/DisplaySettingsButton.tsx
+++ b/apps/studio/components/interfaces/Explorer/QueryCell/DisplaySettingsButton.tsx
@@ -1,4 +1,5 @@
import { BarChart2, Settings2, Table } from 'lucide-react'
+import { useEffect, useEffectEvent, useMemo } from 'react'
import {
Checkbox,
Popover,
@@ -12,23 +13,34 @@ import {
SelectValue,
ToggleGroup,
ToggleGroupItem,
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { type Snapshot } from 'valtio'
import { ExplorerToolbarAction } from '../ExplorerToolbar'
+import { type QueryResult } from '../types'
+import { checkHasNonPositiveValues } from '@/components/ui/QueryBlock/QueryBlock.utils'
import { type DatabaseCell as DatabaseCellSchema } from '@/data/content/notebooks/notebook-schema'
import { useCurrentNotebook, useNotebooksStateSnapshot } from '@/state/notebooks/notebooks-state'
interface DisplaySettingsButtonProps {
cell: Snapshot
+ result?: QueryResult
columns: string[]
disabled: boolean
}
// [Joshen] TODO support multiple y axis charts
-export const DisplaySettingsButton = ({ cell, columns, disabled }: DisplaySettingsButtonProps) => {
+export const DisplaySettingsButton = ({
+ cell,
+ result,
+ columns,
+ disabled,
+}: DisplaySettingsButtonProps) => {
const snap = useNotebooksStateSnapshot()
const currentNotebook = useCurrentNotebook()
const cells = currentNotebook?.notebook.content?.cells ?? []
@@ -37,12 +49,22 @@ export const DisplaySettingsButton = ({ cell, columns, disabled }: DisplaySettin
const {
type = 'bar',
x_column,
- y_columns,
+ y_columns = [],
cumulative = false,
show_labels = false,
scale = 'linear',
} = chart ?? {}
+ const hasNonPositiveValues = useMemo(
+ () => checkHasNonPositiveValues(result?.rows ?? [], y_columns[0]),
+ [result, y_columns]
+ )
+
+ const canToggleLogScale = useMemo(() => {
+ if (y_columns.length === 0 || !result || (result.rows ?? []).length === 0) return false
+ return !hasNonPositiveValues
+ }, [hasNonPositiveValues, result, y_columns.length])
+
const onChangeView = (view: 'table' | 'chart') => {
const notebookId = currentNotebook?.notebook.id
if (!notebookId) return
@@ -84,12 +106,22 @@ export const DisplaySettingsButton = ({ cell, columns, disabled }: DisplaySettin
snap.updateCells({ id: notebookId, cells: nextCells })
}
+ const resetToLinearScale = useEffectEvent(() => {
+ onUpdateChartConfig({ scale: 'linear' })
+ })
+
+ useEffect(() => {
+ if (hasNonPositiveValues && scale === 'log') {
+ resetToLinearScale()
+ }
+ }, [hasNonPositiveValues, scale])
+
return (
} tooltip="Result settings" />
-
+
Result display settings
@@ -187,7 +219,24 @@ export const DisplaySettingsButton = ({ cell, columns, disabled }: DisplaySettin
Linear
- Logarithmic
+
+
+
+ Logarithmic
+
+
+ {!canToggleLogScale && (
+
+ {y_columns.length === 0
+ ? 'Select a column for the Y axis first'
+ : 'Data contains zero or negative values'}
+
+ )}
+
diff --git a/apps/studio/components/interfaces/Explorer/QueryCell/QueryResultChart.tsx b/apps/studio/components/interfaces/Explorer/QueryCell/QueryResultChart.tsx
index 8f6db1ffc8c47..ddee91b17b7f5 100644
--- a/apps/studio/components/interfaces/Explorer/QueryCell/QueryResultChart.tsx
+++ b/apps/studio/components/interfaces/Explorer/QueryCell/QueryResultChart.tsx
@@ -4,7 +4,7 @@ import { type Snapshot } from 'valtio'
import { type QueryResult } from '../types'
import NoDataPlaceholder from '@/components/ui/Charts/NoDataPlaceholder'
-import { getCumulativeResults } from '@/components/ui/QueryBlock/QueryBlock.utils'
+import { formatLogTick, getCumulativeResults } from '@/components/ui/QueryBlock/QueryBlock.utils'
import { type DatabaseCell as DatabaseCellSchema } from '@/data/content/notebooks/notebook-schema'
interface QueryResultChartProps {
@@ -23,7 +23,7 @@ const toChartValue = (value: unknown): string | number => {
export const QueryResultChart = ({ cell, result }: QueryResultChartProps) => {
const { chart } = cell
- const { type, x_column, y_columns = [], cumulative, show_labels } = chart ?? {}
+ const { type, x_column, y_columns = [], cumulative, show_labels, scale } = chart ?? {}
const hasConfig = !!x_column && y_columns.length > 0
const chartRows = useMemo(() => {
@@ -76,6 +76,11 @@ export const QueryResultChart = ({ cell, result }: QueryResultChartProps) => {
showXAxis={show_labels}
showYAxis={show_labels}
data={resultToRender}
+ YAxisProps={{
+ scale: scale === 'log' ? 'log' : 'auto',
+ domain: scale === 'log' ? [1, 'auto'] : undefined,
+ tickFormatter: scale === 'log' ? formatLogTick : undefined,
+ }}
/>
)}
{type === 'line' && (
@@ -86,6 +91,11 @@ export const QueryResultChart = ({ cell, result }: QueryResultChartProps) => {
showXAxis={show_labels}
showYAxis={show_labels}
data={resultToRender}
+ YAxisProps={{
+ scale: scale === 'log' ? 'log' : 'auto',
+ domain: scale === 'log' ? [1, 'auto'] : undefined,
+ tickFormatter: scale === 'log' ? formatLogTick : undefined,
+ }}
/>
)}
diff --git a/apps/studio/components/interfaces/Explorer/QueryCell/index.tsx b/apps/studio/components/interfaces/Explorer/QueryCell/index.tsx
index bf225ba54c55a..2a2a6a8ff1f6f 100644
--- a/apps/studio/components/interfaces/Explorer/QueryCell/index.tsx
+++ b/apps/studio/components/interfaces/Explorer/QueryCell/index.tsx
@@ -120,6 +120,7 @@ export const QueryCell = ({ cell }: QueryCellProps) => {
diff --git a/packages/ui-patterns/src/Chart/charts/chart-bar.tsx b/packages/ui-patterns/src/Chart/charts/chart-bar.tsx
index 79c0f16f512ea..e81034adabb74 100644
--- a/packages/ui-patterns/src/Chart/charts/chart-bar.tsx
+++ b/packages/ui-patterns/src/Chart/charts/chart-bar.tsx
@@ -73,6 +73,9 @@ export interface ChartBarProps {
}
}
+// [Joshen] JFYI - shouldn't rely on xKey's value to determine if its a time-based format
+// Preferably provide an additional param like xFormat to be more deterministic
+
export const ChartBar = ({
data,
xKey = 'timestamp',
diff --git a/packages/ui-patterns/src/Chart/charts/chart-line.tsx b/packages/ui-patterns/src/Chart/charts/chart-line.tsx
index 1811933d845a0..a2571ff78c540 100644
--- a/packages/ui-patterns/src/Chart/charts/chart-line.tsx
+++ b/packages/ui-patterns/src/Chart/charts/chart-line.tsx
@@ -84,6 +84,9 @@ export interface ChartLineProps {
referenceLines?: ChartReferenceLine[]
}
+// [Joshen] JFYI - shouldn't rely on xKey's value to determine if its a time-based format
+// Preferably provide an additional param like xFormat to be more deterministic
+
export const ChartLine = ({
data,
xKey = 'timestamp',
@@ -305,7 +308,7 @@ export const ChartLine = ({
fillOpacity={fillOpacity}
stroke={lineColor}
strokeWidth={strokeWidth}
- stackId={`stack-${key}`}
+ stackId={keysToRender.length > 1 ? `stack-${key}` : undefined}
/>
)
})}
From cc6fe2100a728dfa3d63b8bb647247c883b97b8e Mon Sep 17 00:00:00 2001
From: Saxon Fletcher
Date: Thu, 13 Aug 2026 19:51:06 +1000
Subject: [PATCH 6/6] refactor(studio): centralize query sources (#49027)
## Summary
- define application-owned database and logs source contracts, defaults,
validation, labels, and execution endpoints
- extract controlled database and logs parameter controls for reuse
outside SQL snippets
- adapt the SQL editor to the shared source model without changing
snippet behavior
- standardize source icons at 16px with a 2px stroke
- keep relative logs ranges aligned with the existing date picker units
## To test
1. Open an existing query in the SQL Editor and run it against the
database.
2. Switch the query source to Logs, change the time range, and confirm
the query still runs as expected.
## Why
Explorer queries and notebook query cells need to select an execution
source without coupling that source to SQL snippets. This provides the
shared registry and controlled UI foundation for those consumers.
## Impact
Existing SQL snippets retain their current database/logs routing and
session behavior. The registry documents the SQL editor legacy
database-selector adapter while new consumers own their identifier
inline. The shared Logs date picker remains unchanged; query ranges
support its existing minute, hour, and day units. This PR does not add
the Explorer query tab itself.
## Validation
- pnpm --filter studio typecheck
- focused Vitest coverage for the registry, canonical log-range
utilities, SQL execution adapters, source filtering, retention locking,
custom ranges, and preset selection
- pnpm --filter studio run lint:ratchet
Component and state tests cover this change per the Studio testing
guidance; no E2E test is added.
## Summary by CodeRabbit
* **New Features**
* Added a unified query-source menu for database queries and logs.
* Added custom log time-range selection with calendar support and
retention-aware upgrade prompts.
* Added consistent source icons and improved database selection
handling.
* Added support for relative and absolute log time ranges.
* **Bug Fixes**
* Improved log-range validation, defaults, and current-time handling.
* Updated query execution to use the correct source-specific endpoints.
* **Tests**
* Expanded coverage for query sources, log ranges, menus, and retention
behavior.
---
.../DatabaseParametersSubMenu.tsx} | 31 +--
.../QuerySources/LogTimeRange.utils.test.ts | 114 ++++++++
.../QuerySources/LogTimeRange.utils.ts | 97 +++++++
.../LogsCustomRangeDialog.tsx | 0
.../LogsTimeRangeSubMenu.test.tsx | 57 ++++
.../LogsTimeRangeSubMenu.tsx} | 27 +-
.../QuerySources/QuerySourceIcon.tsx | 15 ++
.../QuerySources/useLogsCustomRange.ts | 35 +++
.../QuerySourceMenu/QuerySourceMenu.tsx | 121 ++++-----
.../interfaces/SQLEditor/querySource.test.ts | 252 +-----------------
.../interfaces/SQLEditor/querySource.ts | 130 +--------
.../SQLEditor/useLogsSqlExecution.test.tsx | 5 +-
.../SQLEditor/useLogsSqlExecution.ts | 13 +-
.../SQLEditor/useRunSource.test.tsx | 11 +-
.../interfaces/SQLEditor/useRunSource.ts | 10 +-
.../query-source-registry.test.ts | 116 ++++++++
.../query-sources/query-source-registry.ts | 152 +++++++++++
apps/studio/data/sql/execute-sql-mutation.ts | 3 +-
.../sql-editor/sql-editor-session-state.ts | 8 +-
.../SQLEditor/QuerySourceMenu.test.tsx | 68 +++--
.../features/logs/Logs.Datepickers.test.tsx | 4 +-
21 files changed, 735 insertions(+), 534 deletions(-)
rename apps/studio/components/interfaces/{SQLEditor/UtilityPanel/QuerySourceMenu/DatabaseSubMenu.tsx => QuerySources/DatabaseParametersSubMenu.tsx} (74%)
create mode 100644 apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.test.ts
create mode 100644 apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.ts
rename apps/studio/components/interfaces/{SQLEditor/UtilityPanel/QuerySourceMenu => QuerySources}/LogsCustomRangeDialog.tsx (100%)
create mode 100644 apps/studio/components/interfaces/QuerySources/LogsTimeRangeSubMenu.test.tsx
rename apps/studio/components/interfaces/{SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx => QuerySources/LogsTimeRangeSubMenu.tsx} (80%)
create mode 100644 apps/studio/components/interfaces/QuerySources/QuerySourceIcon.tsx
create mode 100644 apps/studio/components/interfaces/QuerySources/useLogsCustomRange.ts
create mode 100644 apps/studio/data/query-sources/query-source-registry.test.ts
create mode 100644 apps/studio/data/query-sources/query-source-registry.ts
diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/DatabaseSubMenu.tsx b/apps/studio/components/interfaces/QuerySources/DatabaseParametersSubMenu.tsx
similarity index 74%
rename from apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/DatabaseSubMenu.tsx
rename to apps/studio/components/interfaces/QuerySources/DatabaseParametersSubMenu.tsx
index 59458d69a99b6..f946f4e03f848 100644
--- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/DatabaseSubMenu.tsx
+++ b/apps/studio/components/interfaces/QuerySources/DatabaseParametersSubMenu.tsx
@@ -1,4 +1,4 @@
-import { LOCAL_STORAGE_KEYS, useParams } from 'common'
+import { useParams } from 'common'
import { Check, Plus } from 'lucide-react'
import Link from 'next/link'
import {
@@ -12,9 +12,6 @@ import {
import { useReadReplicasQuery } from '@/data/read-replicas/replicas-query'
import { formatDatabaseID, formatDatabaseRegion } from '@/data/read-replicas/replicas.utils'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
-import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
-import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector'
-import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state'
/** The label a database row/summary shows: the primary, or a replica by region + id. */
function databaseLabel(identifier: string, region: string, projectRef: string | undefined) {
@@ -22,35 +19,27 @@ function databaseLabel(identifier: string, region: string, projectRef: string |
return `Read replica (${formatDatabaseRegion(region)} - ${formatDatabaseID(identifier)})`
}
-export const DatabaseSubMenu = ({ id }: { id: string }) => {
+export const DatabaseParametersSubMenu = ({
+ identifier,
+ onIdentifierChange,
+}: {
+ identifier?: string
+ onIdentifierChange: (identifier: string) => void
+}) => {
const { ref: projectRef } = useParams()
- const sessionSnap = useSqlEditorSessionSnapshot()
- const dbSelector = useDatabaseSelectorStateSnapshot()
const { infrastructureReadReplicas } = useIsFeatureEnabled(['infrastructure:read_replicas'])
- const [lastSelectedDb, setLastSelectedDb] = useLocalStorageQuery(
- LOCAL_STORAGE_KEYS.SQL_EDITOR_LAST_SELECTED_DB(projectRef ?? ''),
- ''
- )
-
const { data } = useReadReplicasQuery({ projectRef })
const databases = (data ?? [])
.slice()
.sort((a, b) => (a.inserted_at > b.inserted_at ? 1 : 0))
.sort((database) => (database.identifier === projectRef ? -1 : 0))
- const selectedDatabaseId =
- lastSelectedDb.length > 0 ? lastSelectedDb : (dbSelector.selectedDatabaseId ?? projectRef)
+ const selectedDatabaseId = identifier ?? projectRef
const selectedDatabase = databases.find((db) => db.identifier === selectedDatabaseId)
const newReplicaURL = `/project/${projectRef}/database/replication?destinationType=Read+Replica`
- const handleSelect = (databaseId: string) => {
- dbSelector.setSelectedDatabaseId(databaseId)
- setLastSelectedDb(databaseId)
- sessionSnap.resetResult(id)
- }
-
return (
@@ -71,7 +60,7 @@ export const DatabaseSubMenu = ({ id }: { id: string }) => {
key={database.identifier}
className="justify-between"
disabled={isUnhealthy}
- onClick={() => handleSelect(database.identifier)}
+ onClick={() => onIdentifierChange(database.identifier)}
>
{databaseLabel(database.identifier, database.region, projectRef)}
{database.identifier === selectedDatabaseId && }
diff --git a/apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.test.ts b/apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.test.ts
new file mode 100644
index 0000000000000..f12ec9cef6624
--- /dev/null
+++ b/apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.test.ts
@@ -0,0 +1,114 @@
+import dayjs from 'dayjs'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+
+import {
+ customDateRangeToLogTimeRange,
+ datePickerValueToLogTimeRange,
+ logTimeRangesEqual,
+ logTimeRangeToDatePickerValue,
+ resolveLogTimeRange,
+} from './LogTimeRange.utils'
+import { generateDynamicHelper } from '@/components/interfaces/Settings/Logs/Logs.datePickerHelpers'
+import {
+ DEFAULT_LOG_TIME_RANGE,
+ type LogTimeRange,
+} from '@/data/query-sources/query-source-registry'
+
+describe('LogTimeRange.utils', () => {
+ beforeEach(() => {
+ vi.useFakeTimers()
+ vi.setSystemTime(new Date('2025-01-08T12:00:00.000Z'))
+ })
+
+ afterEach(() => vi.useRealTimers())
+
+ it.each([
+ ['30m', 30, 'minute'],
+ ['2h', 2, 'hour'],
+ ['7d', 7, 'day'],
+ ] as const)('round-trips the picker helper for %s', (_, amount, unit) => {
+ const helper = generateDynamicHelper(amount, unit)
+ const pickerValue = {
+ from: helper.calcFrom(),
+ to: helper.calcTo(),
+ isHelper: true,
+ text: helper.text,
+ }
+ const range: LogTimeRange = { type: 'relative', amount, unit }
+
+ expect(datePickerValueToLogTimeRange(pickerValue)).toEqual(range)
+ expect(logTimeRangeToDatePickerValue(range)).toEqual(pickerValue)
+ })
+
+ it('falls back to the default when a custom value has no valid start', () => {
+ expect(datePickerValueToLogTimeRange({ from: '', to: '', isHelper: false })).toEqual(
+ DEFAULT_LOG_TIME_RANGE
+ )
+ })
+
+ it('uses now when an absolute helper has an empty end', () => {
+ expect(
+ datePickerValueToLogTimeRange({
+ from: '2025-01-01T00:00:00.000Z',
+ to: '',
+ isHelper: true,
+ text: 'Custom',
+ })
+ ).toEqual({
+ type: 'absolute',
+ from: '2025-01-01T00:00:00.000Z',
+ to: '2025-01-08T12:00:00.000Z',
+ })
+ })
+
+ it('compares relative and absolute ranges structurally', () => {
+ expect(
+ logTimeRangesEqual(
+ { type: 'relative', amount: 1, unit: 'hour' },
+ { type: 'relative', amount: 1, unit: 'hour' }
+ )
+ ).toBe(true)
+ expect(
+ logTimeRangesEqual(
+ { type: 'relative', amount: 1, unit: 'hour' },
+ { type: 'relative', amount: 1, unit: 'day' }
+ )
+ ).toBe(false)
+ expect(
+ logTimeRangesEqual(
+ { type: 'absolute', from: '2025-01-01T00:00:00.000Z', to: '2025-01-02T00:00:00.000Z' },
+ { type: 'absolute', from: '2025-01-01T00:00:00.000Z', to: '2025-01-02T00:00:00.000Z' }
+ )
+ ).toBe(true)
+ })
+
+ it('resolves a relative range against the current time', () => {
+ expect(resolveLogTimeRange({ type: 'relative', amount: 2, unit: 'day' })).toEqual({
+ from: dayjs().subtract(2, 'day').toISOString(),
+ to: dayjs().toISOString(),
+ })
+ })
+
+ it('passes an absolute range through unchanged', () => {
+ const range: LogTimeRange = {
+ type: 'absolute',
+ from: '2025-01-01T00:00:00.000Z',
+ to: '2025-01-02T00:00:00.000Z',
+ }
+ expect(resolveLogTimeRange(range)).toEqual({ from: range.from, to: range.to })
+ })
+
+ it('clamps a custom range ending today to now', () => {
+ const from = new Date('2025-01-07T09:00:00.000Z')
+ expect(
+ customDateRangeToLogTimeRange({
+ from,
+ to: new Date('2025-01-08T09:00:00.000Z'),
+ })
+ ).toEqual({
+ type: 'absolute',
+ from: dayjs(from).startOf('day').toISOString(),
+ to: '2025-01-08T12:00:00.000Z',
+ })
+ })
+})
diff --git a/apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.ts b/apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.ts
new file mode 100644
index 0000000000000..4dd9f9ff10078
--- /dev/null
+++ b/apps/studio/components/interfaces/QuerySources/LogTimeRange.utils.ts
@@ -0,0 +1,97 @@
+import dayjs from 'dayjs'
+
+import { generateDynamicHelper } from '@/components/interfaces/Settings/Logs/Logs.datePickerHelpers'
+import type { DatePickerValue } from '@/components/interfaces/Settings/Logs/Logs.DatePickers'
+import type { ResolvedLogDateRange } from '@/components/interfaces/Settings/Logs/logsDateRange'
+import {
+ DEFAULT_LOG_TIME_RANGE,
+ type LogTimeRange,
+} from '@/data/query-sources/query-source-registry'
+import { isoDateTimeString, type IsoDateTimeString } from '@/lib/iso-datetime'
+
+export type RelativeTimeUnit = Extract['unit']
+
+const nowIsoDateTime = (): IsoDateTimeString => dayjs().toISOString() as IsoDateTimeString
+
+function parseRelativeHelperLabel(
+ text: string | undefined
+): { amount: number; unit: RelativeTimeUnit } | null {
+ if (!text) return null
+ const match = text
+ .trim()
+ .toLowerCase()
+ .match(/^last\s+(?:(\d+)\s+)?(minute|hour|day)s?$/)
+ if (!match) return null
+
+ const amount = match[1] ? parseInt(match[1], 10) : 1
+ if (!Number.isFinite(amount) || amount <= 0) return null
+
+ const unit = match[2]
+ if (unit !== 'minute' && unit !== 'hour' && unit !== 'day') return null
+ return { amount, unit }
+}
+
+export function datePickerValueToLogTimeRange(value: DatePickerValue): LogTimeRange {
+ if (value.isHelper) {
+ const relative = parseRelativeHelperLabel(value.text)
+ if (relative) return { type: 'relative', ...relative }
+ }
+
+ const from = isoDateTimeString(value.from)
+ if (from === null) return DEFAULT_LOG_TIME_RANGE
+ const to = isoDateTimeString(value.to) ?? nowIsoDateTime()
+ return { type: 'absolute', from, to }
+}
+
+export function logTimeRangeToDatePickerValue(range: LogTimeRange): DatePickerValue {
+ if (range.type === 'relative') {
+ const helper = generateDynamicHelper(range.amount, range.unit)
+ return {
+ from: helper.calcFrom(),
+ to: helper.calcTo(),
+ isHelper: true,
+ text: helper.text,
+ }
+ }
+ return { from: range.from, to: range.to, isHelper: false }
+}
+
+export function customDateRangeToLogTimeRange({
+ from,
+ to,
+ now = new Date(),
+}: {
+ from: Date
+ to: Date
+ now?: Date
+}): Extract {
+ const nowValue = dayjs(now)
+ const requestedTo = dayjs(to).endOf('day')
+
+ return {
+ type: 'absolute',
+ from: dayjs(from).startOf('day').toISOString(),
+ to: requestedTo.isAfter(nowValue) ? nowValue.toISOString() : requestedTo.toISOString(),
+ }
+}
+
+export function logTimeRangesEqual(a: LogTimeRange, b: LogTimeRange): boolean {
+ if (a.type === 'relative' && b.type === 'relative') {
+ return a.amount === b.amount && a.unit === b.unit
+ }
+ if (a.type === 'absolute' && b.type === 'absolute') {
+ return a.from === b.from && a.to === b.to
+ }
+ return false
+}
+
+export function resolveLogTimeRange(range: LogTimeRange): ResolvedLogDateRange {
+ if (range.type === 'relative') {
+ const now = dayjs()
+ return {
+ from: now.subtract(range.amount, range.unit).toISOString(),
+ to: now.toISOString(),
+ }
+ }
+ return { from: range.from, to: range.to }
+}
diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/LogsCustomRangeDialog.tsx b/apps/studio/components/interfaces/QuerySources/LogsCustomRangeDialog.tsx
similarity index 100%
rename from apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/LogsCustomRangeDialog.tsx
rename to apps/studio/components/interfaces/QuerySources/LogsCustomRangeDialog.tsx
diff --git a/apps/studio/components/interfaces/QuerySources/LogsTimeRangeSubMenu.test.tsx b/apps/studio/components/interfaces/QuerySources/LogsTimeRangeSubMenu.test.tsx
new file mode 100644
index 0000000000000..80d4c0fac1c4a
--- /dev/null
+++ b/apps/studio/components/interfaces/QuerySources/LogsTimeRangeSubMenu.test.tsx
@@ -0,0 +1,57 @@
+import { screen } from '@testing-library/react'
+import userEvent from '@testing-library/user-event'
+import { mockAnimationsApi } from 'jsdom-testing-mocks'
+import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from 'ui'
+import { describe, expect, it, vi } from 'vitest'
+
+import { LogsTimeRangeSubMenu } from './LogsTimeRangeSubMenu'
+import { customRender } from '@/tests/lib/custom-render'
+
+mockAnimationsApi()
+
+vi.mock('@/hooks/misc/useCheckEntitlements', () => ({
+ useCheckEntitlements: () => ({ getEntitlementNumericValue: () => 1 }),
+}))
+
+const renderSubMenu = ({
+ onRangeChange = vi.fn(),
+ onOpenCustomRange = vi.fn(),
+ onShowUpgrade = vi.fn(),
+} = {}) => {
+ customRender(
+
+ Open
+
+
+
+
+ )
+
+ return { onRangeChange, onOpenCustomRange, onShowUpgrade }
+}
+
+describe('LogsTimeRangeSubMenu', () => {
+ it('opens the upgrade prompt instead of applying a range beyond retention', async () => {
+ const { onRangeChange, onShowUpgrade } = renderSubMenu()
+
+ await userEvent.hover(await screen.findByText('Time range'))
+ await userEvent.click(await screen.findByText('Last 7 days'))
+
+ expect(onShowUpgrade).toHaveBeenCalledOnce()
+ expect(onRangeChange).not.toHaveBeenCalled()
+ })
+
+ it('exposes the custom-range action', async () => {
+ const { onOpenCustomRange } = renderSubMenu()
+
+ await userEvent.hover(await screen.findByText('Time range'))
+ await userEvent.click(await screen.findByText('Custom range…'))
+
+ expect(onOpenCustomRange).toHaveBeenCalledOnce()
+ })
+})
diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx b/apps/studio/components/interfaces/QuerySources/LogsTimeRangeSubMenu.tsx
similarity index 80%
rename from apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx
rename to apps/studio/components/interfaces/QuerySources/LogsTimeRangeSubMenu.tsx
index f633d4a8a58be..9830e206a14c4 100644
--- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx
+++ b/apps/studio/components/interfaces/QuerySources/LogsTimeRangeSubMenu.tsx
@@ -8,42 +8,37 @@ import {
DropdownMenuSubTrigger,
} from 'ui'
-import {
- datePickerValueToLogDateRange,
- logDateRangesEqual,
- type LogDateRange,
-} from '../../querySource'
+import { datePickerValueToLogTimeRange, logTimeRangesEqual } from './LogTimeRange.utils'
import { EXPLORER_DATEPICKER_HELPERS } from '@/components/interfaces/Settings/Logs/Logs.constants'
import { maybeShowUpgradePromptIfNotEntitled } from '@/components/interfaces/Settings/Logs/Logs.utils'
+import type { LogTimeRange } from '@/data/query-sources/query-source-registry'
import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
-import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state'
-export const TimeRangeSubMenu = ({
- id,
+export const LogsTimeRangeSubMenu = ({
range,
+ onRangeChange,
onOpenCustomRange,
onShowUpgrade,
}: {
- id: string
- range: LogDateRange
+ range: LogTimeRange
+ onRangeChange: (range: LogTimeRange) => void
onOpenCustomRange: () => void
onShowUpgrade: () => void
}) => {
- const sessionSnap = useSqlEditorSessionSnapshot()
const { getEntitlementNumericValue } = useCheckEntitlements('log.retention_days')
const entitledToLogDays = getEntitlementNumericValue()
- const isCustomRange = range.kind === 'absolute'
+ const isCustomRange = range.type === 'absolute'
const presets = EXPLORER_DATEPICKER_HELPERS.map((helper) => ({
helper,
- range: datePickerValueToLogDateRange({
+ range: datePickerValueToLogTimeRange({
from: helper.calcFrom(),
to: helper.calcTo(),
isHelper: true,
text: helper.text,
}),
}))
- const selectedPreset = presets.find((preset) => logDateRangesEqual(range, preset.range))
+ const selectedPreset = presets.find((preset) => logTimeRangesEqual(range, preset.range))
return (
@@ -59,7 +54,7 @@ export const TimeRangeSubMenu = ({
{presets.map(({ helper, range: presetRange }) => {
- const isSelected = !isCustomRange && logDateRangesEqual(range, presetRange)
+ const isSelected = !isCustomRange && logTimeRangesEqual(range, presetRange)
const isLocked = maybeShowUpgradePromptIfNotEntitled(helper.calcFrom(), entitledToLogDays)
return (
@@ -68,7 +63,7 @@ export const TimeRangeSubMenu = ({
className="justify-between"
onClick={() => {
if (isLocked) return onShowUpgrade()
- sessionSnap.setLogRange(id, presetRange)
+ onRangeChange(presetRange)
}}
>
{helper.text}
diff --git a/apps/studio/components/interfaces/QuerySources/QuerySourceIcon.tsx b/apps/studio/components/interfaces/QuerySources/QuerySourceIcon.tsx
new file mode 100644
index 0000000000000..a1d635866ba00
--- /dev/null
+++ b/apps/studio/components/interfaces/QuerySources/QuerySourceIcon.tsx
@@ -0,0 +1,15 @@
+import { Database, ScrollText } from 'lucide-react'
+
+import type { QuerySourceId } from '@/data/query-sources/query-source-registry'
+
+export const QuerySourceIcon = ({
+ source,
+ className,
+}: {
+ source: QuerySourceId
+ className?: string
+}) => {
+ const props = { className, size: 16, strokeWidth: 2 }
+
+ return source === 'logs' ? :
+}
diff --git a/apps/studio/components/interfaces/QuerySources/useLogsCustomRange.ts b/apps/studio/components/interfaces/QuerySources/useLogsCustomRange.ts
new file mode 100644
index 0000000000000..43e103d82c262
--- /dev/null
+++ b/apps/studio/components/interfaces/QuerySources/useLogsCustomRange.ts
@@ -0,0 +1,35 @@
+import { useState } from 'react'
+
+import { customDateRangeToLogTimeRange } from './LogTimeRange.utils'
+import { maybeShowUpgradePromptIfNotEntitled } from '@/components/interfaces/Settings/Logs/Logs.utils'
+import type { LogTimeRange } from '@/data/query-sources/query-source-registry'
+import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
+
+export function useLogsCustomRange({
+ onRangeChange,
+}: {
+ onRangeChange: (range: LogTimeRange) => void
+}) {
+ const [isCustomRangeOpen, setIsCustomRangeOpen] = useState(false)
+ const [showUpgradePrompt, setShowUpgradePrompt] = useState(false)
+ const { getEntitlementNumericValue } = useCheckEntitlements('log.retention_days')
+ const entitledToLogDays = getEntitlementNumericValue()
+
+ const handleApplyCustomRange = ({ from, to }: { from: Date; to: Date }) => {
+ const range = customDateRangeToLogTimeRange({ from, to })
+ if (maybeShowUpgradePromptIfNotEntitled(range.from, entitledToLogDays)) {
+ setShowUpgradePrompt(true)
+ return
+ }
+
+ onRangeChange(range)
+ }
+
+ return {
+ isCustomRangeOpen,
+ setIsCustomRangeOpen,
+ showUpgradePrompt,
+ setShowUpgradePrompt,
+ handleApplyCustomRange,
+ }
+}
diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx
index 9e08a904d5059..d741dc3535e7f 100644
--- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx
@@ -1,8 +1,6 @@
-import { useParams } from 'common'
-import dayjs from 'dayjs'
-import { Check, ChevronDown, Database, ScrollText } from 'lucide-react'
+import { LOCAL_STORAGE_KEYS, useParams } from 'common'
+import { Check, ChevronDown } from 'lucide-react'
import { useRouter } from 'next/router'
-import { useState } from 'react'
import {
Button,
DropdownMenu,
@@ -12,32 +10,23 @@ import {
DropdownMenuTrigger,
} from 'ui'
-import {
- datePickerValueToLogDateRange,
- type QuerySource,
- type SqlSnippetSource,
-} from '../../querySource'
-import { DatabaseSubMenu } from './DatabaseSubMenu'
-import { LogsCustomRangeDialog } from './LogsCustomRangeDialog'
+import { type QuerySource, type SqlSnippetSource } from '../../querySource'
import { resolveSourceSwitch } from './QuerySourceMenu.utils'
import { RowLimitSubMenu } from './RowLimitSubMenu'
import { RunAsSubMenu } from './RunAsSubMenu'
-import { TimeRangeSubMenu } from './TimeRangeSubMenu'
-import { maybeShowUpgradePromptIfNotEntitled } from '@/components/interfaces/Settings/Logs/Logs.utils'
+import { DatabaseParametersSubMenu } from '@/components/interfaces/QuerySources/DatabaseParametersSubMenu'
+import { LogsCustomRangeDialog } from '@/components/interfaces/QuerySources/LogsCustomRangeDialog'
+import { LogsTimeRangeSubMenu } from '@/components/interfaces/QuerySources/LogsTimeRangeSubMenu'
+import { QuerySourceIcon } from '@/components/interfaces/QuerySources/QuerySourceIcon'
+import { useLogsCustomRange } from '@/components/interfaces/QuerySources/useLogsCustomRange'
import UpgradePrompt from '@/components/interfaces/Settings/Logs/UpgradePrompt'
-import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
+import { QUERY_SOURCE_LABELS, QUERY_SOURCES } from '@/data/query-sources/query-source-registry'
+import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
import { IS_PLATFORM } from '@/lib/constants'
+import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector'
import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state'
import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor/sql-editor-state'
-const SOURCE_LABEL: Record = {
- database: 'Database',
- logs: 'Logs',
-}
-
-const SourceIcon = ({ source, ...props }: { source: SqlSnippetSource; className?: string }) =>
- source === 'logs' ? :
-
type QuerySourceMenuProps = {
id: string
runSource: QuerySource
@@ -67,18 +56,33 @@ export const QuerySourceMenu = ({ id, runSource, canCreateLogsSnippet }: QuerySo
const router = useRouter()
const snapV2 = useSqlEditorV2StateSnapshot()
const sessionSnap = useSqlEditorSessionSnapshot()
+ const databaseSelector = useDatabaseSelectorStateSnapshot()
+ const [lastSelectedDatabase, setLastSelectedDatabase] = useLocalStorageQuery(
+ LOCAL_STORAGE_KEYS.SQL_EDITOR_LAST_SELECTED_DB(ref ?? ''),
+ ''
+ )
- const [isCustomRangeOpen, setIsCustomRangeOpen] = useState(false)
- const [showUpgradePrompt, setShowUpgradePrompt] = useState(false)
-
- const { getEntitlementNumericValue } = useCheckEntitlements('log.retention_days')
- const entitledToLogDays = getEntitlementNumericValue()
+ const {
+ isCustomRangeOpen,
+ setIsCustomRangeOpen,
+ showUpgradePrompt,
+ setShowUpgradePrompt,
+ handleApplyCustomRange,
+ } = useLogsCustomRange({ onRangeChange: (range) => sessionSnap.setLogRange(id, range) })
const currentSource = runSource.type
const isLogs = currentSource === 'logs'
// A snippet materializes in the store on its first keystroke; until then a
// `/sql/new` tab is a blank scaffold with nothing to preserve.
const isBlankNewTab = snapV2.snippets[id] === undefined
+ const databaseIdentifier =
+ lastSelectedDatabase.length > 0
+ ? lastSelectedDatabase
+ : (databaseSelector.selectedDatabaseId ?? ref)
+
+ const selectableSources = QUERY_SOURCES.filter(
+ (source) => source.type !== 'logs' || canCreateLogsSnippet || isLogs
+ )
const switchSource = (target: SqlSnippetSource) => {
const next = resolveSourceSwitch({ ref, target, currentSource, isBlankNewTab })
@@ -86,20 +90,10 @@ export const QuerySourceMenu = ({ id, runSource, canCreateLogsSnippet }: QuerySo
router[next.method](next.url)
}
- const applyCustomRange = ({ from, to }: { from: Date; to: Date }) => {
- const fromIso = dayjs(from).startOf('day').toISOString()
- if (maybeShowUpgradePromptIfNotEntitled(fromIso, entitledToLogDays)) {
- setShowUpgradePrompt(true)
- return
- }
- sessionSnap.setLogRange(
- id,
- datePickerValueToLogDateRange({
- from: fromIso,
- to: dayjs(to).endOf('day').toISOString(),
- isHelper: false,
- })
- )
+ const updateDatabaseIdentifier = (identifier: string) => {
+ databaseSelector.setSelectedDatabaseId(identifier)
+ setLastSelectedDatabase(identifier)
+ sessionSnap.resetResult(id)
}
return (
@@ -108,55 +102,48 @@ export const QuerySourceMenu = ({ id, runSource, canCreateLogsSnippet }: QuerySo
}
+ aria-label={`Query source: ${QUERY_SOURCE_LABELS[currentSource]}`}
+ icon={}
iconRight={}
>
- {SOURCE_LABEL[currentSource]}
+ {QUERY_SOURCE_LABELS[currentSource]}
- {
- e.preventDefault()
- switchSource('database')
- }}
- >
-
-
- Database
-
- {!isLogs && }
-
- {(canCreateLogsSnippet || isLogs) && (
+ {selectableSources.map((source) => (
{
e.preventDefault()
- switchSource('logs')
+ switchSource(source.id)
}}
>
-
- Logs
+
+ {QUERY_SOURCE_LABELS[source.id]}
- {isLogs && }
+ {currentSource === source.id && }
- )}
+ ))}
{runSource.type === 'logs' ? (
- sessionSnap.setLogRange(id, range)}
onOpenCustomRange={() => setIsCustomRangeOpen(true)}
onShowUpgrade={() => setShowUpgradePrompt(true)}
/>
) : (
<>
- {IS_PLATFORM && }
+ {IS_PLATFORM && (
+
+ )}
>
@@ -169,7 +156,7 @@ export const QuerySourceMenu = ({ id, runSource, canCreateLogsSnippet }: QuerySo
>
diff --git a/apps/studio/components/interfaces/SQLEditor/querySource.test.ts b/apps/studio/components/interfaces/SQLEditor/querySource.test.ts
index 6c68f56e2db46..93f38dcfa7278 100644
--- a/apps/studio/components/interfaces/SQLEditor/querySource.test.ts
+++ b/apps/studio/components/interfaces/SQLEditor/querySource.test.ts
@@ -1,43 +1,11 @@
-import dayjs from 'dayjs'
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { describe, expect, it } from 'vitest'
import {
- datePickerValueToLogDateRange,
- DEFAULT_LOG_DATE_RANGE,
getSnippetSource,
isLogsSource,
- logDateRangesEqual,
- logDateRangeToDatePickerValue,
- resolveLogRunRange,
resolveSnippetSource,
sqlSourceToFenceLanguage,
- type LogDateRange,
} from './querySource'
-import {
- EXPLORER_DATEPICKER_HELPERS,
- getDefaultHelper,
-} from '@/components/interfaces/Settings/Logs/Logs.constants'
-import { generateHelpersFromInput } from '@/components/interfaces/Settings/Logs/Logs.datePickerHelpers'
-import type { DatePickerValue } from '@/components/interfaces/Settings/Logs/Logs.DatePickers'
-import type { DatetimeHelper } from '@/components/interfaces/Settings/Logs/Logs.types'
-import { isoDateTimeString } from '@/lib/iso-datetime'
-
-/** Build the `DatePickerValue` the Logs picker submits when a helper is selected. */
-const valueFromHelper = (helper: DatetimeHelper): DatePickerValue => ({
- from: helper.calcFrom(),
- to: helper.calcTo(),
- isHelper: true,
- text: helper.text,
-})
-
-/** The single dynamic helper produced from typed input like "2h" / "30m". */
-const dynamicHelper = (input: string): DatetimeHelper => {
- const generated = generateHelpersFromInput(input)
- if (!generated || generated.length !== 1) {
- throw new Error(`Expected a single dynamic helper for "${input}"`)
- }
- return generated[0]
-}
describe('querySource.ts:getSnippetSource', () => {
it('maps log_sql to the logs source', () => {
@@ -91,221 +59,3 @@ describe('querySource.ts:resolveSnippetSource', () => {
expect(resolveSnippetSource(undefined, 'nonsense')).toBe('database')
})
})
-
-describe('querySource.ts:datePickerValueToLogDateRange', () => {
- it('parses every static preset into a relative range', () => {
- const cases: Array<[string, { amount: number; unit: 'minute' | 'hour' | 'day' }]> = [
- ['Last hour', { amount: 1, unit: 'hour' }],
- ['Last 3 hours', { amount: 3, unit: 'hour' }],
- ['Last 24 hours', { amount: 24, unit: 'hour' }],
- ['Last 3 days', { amount: 3, unit: 'day' }],
- ['Last 7 days', { amount: 7, unit: 'day' }],
- ]
-
- for (const [text, last] of cases) {
- const helper = EXPLORER_DATEPICKER_HELPERS.find((h) => h.text === text)
- expect(helper, `preset "${text}" exists`).toBeDefined()
- expect(datePickerValueToLogDateRange(valueFromHelper(helper!))).toEqual({
- kind: 'relative',
- last,
- })
- }
- })
-
- it('parses dynamic helpers ("2h", "30m", "7d") into relative ranges', () => {
- expect(datePickerValueToLogDateRange(valueFromHelper(dynamicHelper('2h')))).toEqual({
- kind: 'relative',
- last: { amount: 2, unit: 'hour' },
- })
- expect(datePickerValueToLogDateRange(valueFromHelper(dynamicHelper('30m')))).toEqual({
- kind: 'relative',
- last: { amount: 30, unit: 'minute' },
- })
- expect(datePickerValueToLogDateRange(valueFromHelper(dynamicHelper('7d')))).toEqual({
- kind: 'relative',
- last: { amount: 7, unit: 'day' },
- })
- })
-
- it('treats a preset (calcTo() === "") as relative — the empty end means "now"', () => {
- const lastHour = getDefaultHelper(EXPLORER_DATEPICKER_HELPERS)
- const value = valueFromHelper(lastHour)
- expect(value.to).toBe('')
- expect(datePickerValueToLogDateRange(value)).toEqual({
- kind: 'relative',
- last: { amount: 1, unit: 'hour' },
- })
- })
-
- it('degrades an unparseable helper to an absolute range using from/now (never empty)', () => {
- vi.useFakeTimers()
- const now = new Date('2025-01-01T12:00:00.000Z')
- vi.setSystemTime(now)
-
- const from = '2024-12-31T00:00:00.000Z'
- const result = datePickerValueToLogDateRange({
- from,
- to: '',
- isHelper: true,
- text: 'Some custom label',
- })
-
- expect(result).toEqual({
- kind: 'absolute',
- from,
- to: dayjs(now).toISOString(),
- })
- })
-
- it('maps a custom (non-helper) pick to an absolute range with both endpoints', () => {
- const from = '2025-01-01T00:00:00.000Z'
- const to = '2025-01-02T00:00:00.000Z'
- expect(datePickerValueToLogDateRange({ from, to, isHelper: false })).toEqual({
- kind: 'absolute',
- from,
- to,
- })
- })
-
- it('falls back to the default range when the value has no usable from', () => {
- expect(datePickerValueToLogDateRange({ from: '', to: '', isHelper: false })).toEqual(
- DEFAULT_LOG_DATE_RANGE
- )
- })
-})
-
-describe('querySource.ts:logDateRangeToDatePickerValue', () => {
- beforeEach(() => {
- vi.useFakeTimers()
- vi.setSystemTime(new Date('2025-01-01T12:00:00.000Z'))
- })
-
- it('renders a relative range exactly as the picker would emit the helper', () => {
- const value = logDateRangeToDatePickerValue({
- kind: 'relative',
- last: { amount: 1, unit: 'hour' },
- })
- expect(value).toEqual({
- from: dayjs().subtract(1, 'hour').toISOString(),
- to: dayjs().toISOString(),
- isHelper: true,
- text: 'Last 1 hour',
- })
- })
-
- it('pluralizes the label for amounts greater than one', () => {
- expect(
- logDateRangeToDatePickerValue({ kind: 'relative', last: { amount: 3, unit: 'day' } }).text
- ).toBe('Last 3 days')
- })
-
- it('round-trips through datePickerValueToLogDateRange', () => {
- const range: LogDateRange = { kind: 'relative', last: { amount: 30, unit: 'minute' } }
- expect(datePickerValueToLogDateRange(logDateRangeToDatePickerValue(range))).toEqual(range)
- })
-
- it('passes an absolute range through as a non-helper value', () => {
- const range: LogDateRange = {
- kind: 'absolute',
- from: isoDateTimeString('2025-01-01T00:00:00.000Z')!,
- to: isoDateTimeString('2025-01-02T00:00:00.000Z')!,
- }
- expect(logDateRangeToDatePickerValue(range)).toEqual({
- from: '2025-01-01T00:00:00.000Z',
- to: '2025-01-02T00:00:00.000Z',
- isHelper: false,
- })
- })
-})
-
-describe('querySource.ts:resolveLogRunRange', () => {
- afterEach(() => {
- vi.useRealTimers()
- })
-
- it('re-resolves a relative range against the current time', () => {
- vi.useFakeTimers()
- const now = new Date('2025-06-15T08:30:00.000Z')
- vi.setSystemTime(now)
-
- expect(resolveLogRunRange({ kind: 'relative', last: { amount: 2, unit: 'hour' } })).toEqual({
- from: dayjs(now).subtract(2, 'hour').toISOString(),
- to: dayjs(now).toISOString(),
- })
- })
-
- it('re-resolves the same relative range differently as time advances', () => {
- vi.useFakeTimers()
- vi.setSystemTime(new Date('2025-06-15T08:00:00.000Z'))
- const first = resolveLogRunRange({ kind: 'relative', last: { amount: 1, unit: 'hour' } })
-
- vi.setSystemTime(new Date('2025-06-15T10:00:00.000Z'))
- const second = resolveLogRunRange({ kind: 'relative', last: { amount: 1, unit: 'hour' } })
-
- expect(first).not.toEqual(second)
- expect(second.to).toBe(dayjs('2025-06-15T10:00:00.000Z').toISOString())
- })
-
- it('passes an absolute range through unchanged', () => {
- const from = isoDateTimeString('2025-01-01T00:00:00.000Z')!
- const to = isoDateTimeString('2025-01-02T00:00:00.000Z')!
- expect(resolveLogRunRange({ kind: 'absolute', from, to })).toEqual({
- from: '2025-01-01T00:00:00.000Z',
- to: '2025-01-02T00:00:00.000Z',
- })
- })
-})
-
-describe('querySource.ts:logDateRangesEqual', () => {
- it('matches relative ranges on amount + unit regardless of label formatting', () => {
- const lastHourPreset = EXPLORER_DATEPICKER_HELPERS.find((h) => h.text === 'Last hour')!
- const presetRange = datePickerValueToLogDateRange({
- from: lastHourPreset.calcFrom(),
- to: lastHourPreset.calcTo(),
- isHelper: true,
- text: lastHourPreset.text,
- })
-
- expect(
- logDateRangesEqual(presetRange, { kind: 'relative', last: { amount: 1, unit: 'hour' } })
- ).toBe(true)
- })
-
- it('does not match relative ranges with a different amount or unit', () => {
- expect(
- logDateRangesEqual(
- { kind: 'relative', last: { amount: 1, unit: 'hour' } },
- { kind: 'relative', last: { amount: 3, unit: 'hour' } }
- )
- ).toBe(false)
- expect(
- logDateRangesEqual(
- { kind: 'relative', last: { amount: 1, unit: 'hour' } },
- { kind: 'relative', last: { amount: 1, unit: 'day' } }
- )
- ).toBe(false)
- })
-
- it('matches absolute ranges on their ISO endpoints', () => {
- const from = isoDateTimeString('2025-01-01T00:00:00.000Z')!
- const to = isoDateTimeString('2025-01-02T00:00:00.000Z')!
- expect(logDateRangesEqual({ kind: 'absolute', from, to }, { kind: 'absolute', from, to })).toBe(
- true
- )
- })
-
- it('never matches a relative range against an absolute one', () => {
- const from = isoDateTimeString('2025-01-01T00:00:00.000Z')!
- const to = isoDateTimeString('2025-01-02T00:00:00.000Z')!
- expect(
- logDateRangesEqual(
- { kind: 'relative', last: { amount: 1, unit: 'hour' } },
- {
- kind: 'absolute',
- from,
- to,
- }
- )
- ).toBe(false)
- })
-})
diff --git a/apps/studio/components/interfaces/SQLEditor/querySource.ts b/apps/studio/components/interfaces/SQLEditor/querySource.ts
index 4a1174f837537..49f57612446ce 100644
--- a/apps/studio/components/interfaces/SQLEditor/querySource.ts
+++ b/apps/studio/components/interfaces/SQLEditor/querySource.ts
@@ -1,11 +1,5 @@
-import dayjs from 'dayjs'
-
-import type { Unit } from '@/components/interfaces/Settings/Logs/Logs.datePickerHelpers'
-import { generateDynamicHelper } from '@/components/interfaces/Settings/Logs/Logs.datePickerHelpers'
-import type { DatePickerValue } from '@/components/interfaces/Settings/Logs/Logs.DatePickers'
-import type { ResolvedLogDateRange } from '@/components/interfaces/Settings/Logs/logsDateRange'
import type { Snippet } from '@/data/content/sql-folders-query'
-import { isoDateTimeString, type IsoDateTimeString } from '@/lib/iso-datetime'
+import { type LogTimeRange, type QuerySourceId } from '@/data/query-sources/query-source-registry'
/**
* Domain view of where a snippet's query runs. Derived from the content TYPE:
@@ -14,7 +8,7 @@ import { isoDateTimeString, type IsoDateTimeString } from '@/lib/iso-datetime'
* immutable — switching backends means creating a new snippet, not toggling this
* value.
*/
-export type SqlSnippetSource = 'database' | 'logs'
+export type SqlSnippetSource = QuerySourceId
/**
* The single reader every surface (AI, reports, tabs, nav, execution) uses to
@@ -61,128 +55,10 @@ export function resolveSnippetSource(
return snippet !== undefined ? getSnippetSource(snippet) : parseSqlSnippetSource(sourceParam)
}
-/** `now` as a branded ISO datetime — `toISOString()` is always valid ISO-8601. */
-function nowIsoDateTime(): IsoDateTimeString {
- return dayjs().toISOString() as IsoDateTimeString
-}
-
-/**
- * The units a relative log range is expressed in. Aliases the Logs date picker's
- * `Unit` so the two stay in lockstep rather than drifting as parallel unions.
- */
-export type RelativeTimeUnit = Unit
-
-/**
- * A log query's time range. Relative ranges are structural (amount + unit) and
- * re-resolve against `now` at every run — so a saved "last hour" always means the
- * hour before the run, not the hour before the snippet was opened. Absolute ranges
- * carry validated ISO datetimes and pass through unchanged.
- */
-export type LogDateRange =
- | { kind: 'relative'; last: { amount: number; unit: RelativeTimeUnit } }
- | { kind: 'absolute'; from: IsoDateTimeString; to: IsoDateTimeString }
-
-/** The range a freshly opened logs snippet starts with: the last hour. */
-export const DEFAULT_LOG_DATE_RANGE: LogDateRange = {
- kind: 'relative',
- last: { amount: 1, unit: 'hour' },
-}
-
/**
* The runtime query source for a snippet, pairing the database/logs discriminant
* with the extra state each backend needs to run. A logs run carries the active
* time range (session state, re-resolved at every run); a database run needs
* nothing beyond the connection the execution pipeline already resolves.
*/
-export type QuerySource = { type: 'database' } | { type: 'logs'; dateRange: LogDateRange }
-
-/**
- * Parse a date-picker helper's label (e.g. "Last hour", "Last 3 hours", "Last 30
- * minutes") into a relative amount/unit. Covers both the static presets in
- * `EXPLORER_DATEPICKER_HELPERS` and the dynamic helpers `generateHelpersFromInput`
- * produces from typed input like "2h"/"30m". A label with no number means one unit
- * ("Last hour"). Returns null for any other label.
- */
-function parseRelativeHelperLabel(
- text: string | undefined
-): { amount: number; unit: RelativeTimeUnit } | null {
- if (!text) return null
- const match = text
- .trim()
- .toLowerCase()
- .match(/^last\s+(?:(\d+)\s+)?(minute|hour|day)s?$/)
- if (!match) return null
- const amount = match[1] ? parseInt(match[1], 10) : 1
- if (!Number.isFinite(amount) || amount <= 0) return null
- const unit = match[2]
- if (unit !== 'minute' && unit !== 'hour' && unit !== 'day') return null
- return { amount, unit }
-}
-
-/**
- * Convert a Logs date-picker value into a `LogDateRange`. Helper picks (presets and
- * dynamic "2h"/"30m" helpers) become relative ranges by parsing the helper label;
- * a preset's `calcTo()` resolves to `''` (meaning "now"), which the relative variant
- * models implicitly. Everything else — custom calendar picks, or a helper whose label
- * we can't parse — becomes an absolute range with validated ISO datetimes, degrading
- * via `from`/now rather than rejecting an empty string. A value with no usable `from`
- * falls back to the default range.
- */
-export function datePickerValueToLogDateRange(value: DatePickerValue): LogDateRange {
- if (value.isHelper) {
- const relative = parseRelativeHelperLabel(value.text)
- if (relative) return { kind: 'relative', last: relative }
- }
-
- const from = isoDateTimeString(value.from)
- if (from === null) return DEFAULT_LOG_DATE_RANGE
- const to = isoDateTimeString(value.to) ?? nowIsoDateTime()
- return { kind: 'absolute', from, to }
-}
-
-/**
- * Render a `LogDateRange` back into a Logs date-picker value for display. Relative
- * ranges reuse the picker's own `generateDynamicHelper` to derive the resolved
- * `from`/`to` and matching "Last N unit(s)" label, so the value is byte-for-byte
- * what the picker itself would emit for that helper. Absolute ranges pass their
- * datetimes through.
- */
-export function logDateRangeToDatePickerValue(range: LogDateRange): DatePickerValue {
- if (range.kind === 'relative') {
- const helper = generateDynamicHelper(range.last.amount, range.last.unit)
- return { from: helper.calcFrom(), to: helper.calcTo(), isHelper: true, text: helper.text }
- }
- return { from: range.from, to: range.to, isHelper: false }
-}
-
-/**
- * Structural equality for two log date ranges. Relative ranges match on amount +
- * unit, NOT display text — "Last hour" and "Last 1 hour" render differently but
- * are the same range, so comparing labels is unreliable. Absolute ranges match on
- * their (validated) ISO endpoints.
- */
-export function logDateRangesEqual(a: LogDateRange, b: LogDateRange): boolean {
- if (a.kind === 'relative' && b.kind === 'relative') {
- return a.last.amount === b.last.amount && a.last.unit === b.last.unit
- }
- if (a.kind === 'absolute' && b.kind === 'absolute') {
- return a.from === b.from && a.to === b.to
- }
- return false
-}
-
-/**
- * Resolve a `LogDateRange` to concrete ISO endpoints for a run. Relative ranges
- * re-resolve against `now` (so "last hour" is always the hour before the run);
- * absolute ranges pass through. Reuses the Logs `ResolvedLogDateRange` shape.
- */
-export function resolveLogRunRange(range: LogDateRange): ResolvedLogDateRange {
- if (range.kind === 'relative') {
- const now = dayjs()
- return {
- from: now.subtract(range.last.amount, range.last.unit).toISOString(),
- to: now.toISOString(),
- }
- }
- return { from: range.from, to: range.to }
-}
+export type QuerySource = { type: 'database' } | { type: 'logs'; dateRange: LogTimeRange }
diff --git a/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.test.tsx b/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.test.tsx
index 38e3fb8634b26..97bd6bdd789ee 100644
--- a/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.test.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.test.tsx
@@ -99,8 +99,9 @@ describe('useLogsSqlExecution', () => {
it('resolves a relative session range to a from/to window around now', async () => {
const captured = mockLogsAllOtel([])
sqlEditorSessionState.setLogRange(SNIPPET_ID, {
- kind: 'relative',
- last: { amount: 2, unit: 'hour' },
+ type: 'relative',
+ amount: 2,
+ unit: 'hour',
})
const { result } = renderLogsExecution()
diff --git a/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.ts b/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.ts
index 4c1c006bfd7b0..ddbd7fd3175b7 100644
--- a/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.ts
+++ b/apps/studio/components/interfaces/SQLEditor/useLogsSqlExecution.ts
@@ -1,10 +1,13 @@
import { useFlag, useParams } from 'common'
import { useCallback } from 'react'
-import { DEFAULT_LOG_DATE_RANGE, resolveLogRunRange } from './querySource'
+import { resolveLogTimeRange } from '@/components/interfaces/QuerySources/LogTimeRange.utils'
import { useExecuteLogsSqlMutation } from '@/data/logs/execute-logs-sql-mutation'
-import { logsAllEndpointUrl } from '@/data/logs/logs-endpoint'
import { type SafeLogSqlFragment } from '@/data/logs/safe-analytics-sql'
+import {
+ DEFAULT_LOG_TIME_RANGE,
+ QUERY_SOURCE_REGISTRY,
+} from '@/data/query-sources/query-source-registry'
import { useTrack } from '@/lib/telemetry/track'
import {
getSqlEditorSessionSnapshot,
@@ -46,11 +49,11 @@ export function useLogsSqlExecution({ id }: UseLogsSqlExecutionArgs) {
// Re-read imperatively so a range picked immediately before the run is
// honored; relative ranges re-resolve against `now` here.
- const range = resolveLogRunRange(
- getSqlEditorSessionSnapshot().logRange[id] ?? DEFAULT_LOG_DATE_RANGE
+ const range = resolveLogTimeRange(
+ getSqlEditorSessionSnapshot().logRange[id] ?? DEFAULT_LOG_TIME_RANGE
)
- mutate({ projectRef, sql, range, endpoint: logsAllEndpointUrl(true) })
+ mutate({ projectRef, sql, range, endpoint: QUERY_SOURCE_REGISTRY.logs.endpoint })
track('sql_editor_query_run_button_clicked', { source: 'logs' })
},
diff --git a/apps/studio/components/interfaces/SQLEditor/useRunSource.test.tsx b/apps/studio/components/interfaces/SQLEditor/useRunSource.test.tsx
index 820caa97c00f9..3d63dece309ac 100644
--- a/apps/studio/components/interfaces/SQLEditor/useRunSource.test.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/useRunSource.test.tsx
@@ -1,7 +1,7 @@
import { beforeEach, describe, expect, it } from 'vitest'
-import { DEFAULT_LOG_DATE_RANGE } from './querySource'
import { useRunSource } from './useRunSource'
+import { DEFAULT_LOG_TIME_RANGE } from '@/data/query-sources/query-source-registry'
import { sqlEditorSessionState } from '@/state/sql-editor/sql-editor-session-state'
import {
renderSqlEditorHook,
@@ -31,22 +31,23 @@ describe('useRunSource', () => {
const { result } = renderSqlEditorHook(() => useRunSource(id))
- expect(result.current).toEqual({ type: 'logs', dateRange: DEFAULT_LOG_DATE_RANGE })
+ expect(result.current).toEqual({ type: 'logs', dateRange: DEFAULT_LOG_TIME_RANGE })
})
it('resolves a logs snippet to its session-stored range when one is set', () => {
const id = 'logs-snippet-custom-range'
seedSnippet({ id, source: 'logs' })
sqlEditorSessionState.setLogRange(id, {
- kind: 'relative',
- last: { amount: 2, unit: 'hour' },
+ type: 'relative',
+ amount: 2,
+ unit: 'hour',
})
const { result } = renderSqlEditorHook(() => useRunSource(id))
expect(result.current).toEqual({
type: 'logs',
- dateRange: { kind: 'relative', last: { amount: 2, unit: 'hour' } },
+ dateRange: { type: 'relative', amount: 2, unit: 'hour' },
})
})
})
diff --git a/apps/studio/components/interfaces/SQLEditor/useRunSource.ts b/apps/studio/components/interfaces/SQLEditor/useRunSource.ts
index 95c83d782a597..b9362d4827950 100644
--- a/apps/studio/components/interfaces/SQLEditor/useRunSource.ts
+++ b/apps/studio/components/interfaces/SQLEditor/useRunSource.ts
@@ -1,12 +1,8 @@
import { useParams } from 'common'
import { useMemo } from 'react'
-import {
- DEFAULT_LOG_DATE_RANGE,
- isLogsSource,
- resolveSnippetSource,
- type QuerySource,
-} from './querySource'
+import { isLogsSource, resolveSnippetSource, type QuerySource } from './querySource'
+import { DEFAULT_LOG_TIME_RANGE } from '@/data/query-sources/query-source-registry'
import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state'
import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor/sql-editor-state'
@@ -33,7 +29,7 @@ export function useRunSource(id: string): QuerySource {
return useMemo(() => {
if (isLogsSource(source)) {
- return { type: 'logs', dateRange: logRange ?? DEFAULT_LOG_DATE_RANGE }
+ return { type: 'logs', dateRange: logRange ?? DEFAULT_LOG_TIME_RANGE }
}
return { type: 'database' }
}, [source, logRange])
diff --git a/apps/studio/data/query-sources/query-source-registry.test.ts b/apps/studio/data/query-sources/query-source-registry.test.ts
new file mode 100644
index 0000000000000..03c2045655bcf
--- /dev/null
+++ b/apps/studio/data/query-sources/query-source-registry.test.ts
@@ -0,0 +1,116 @@
+import { describe, expect, it } from 'vitest'
+
+import {
+ cellSourceSchema,
+ createDefaultCellSource,
+ getQuerySource,
+ logTimeRangeSchema,
+ QUERY_SOURCES,
+} from './query-source-registry'
+
+describe('query source registry', () => {
+ it('registers database and logs sources with their execution endpoints', () => {
+ expect(QUERY_SOURCES.map(({ id }) => id)).toEqual(['database', 'logs'])
+ expect(getQuerySource('database').endpoint).toBe('/platform/pg-meta/{ref}/query')
+ expect(getQuerySource('logs').endpoint).toBe(
+ '/platform/projects/{ref}/analytics/endpoints/logs.all.otel'
+ )
+ })
+
+ it('creates independent, valid default cell bindings', () => {
+ const first = createDefaultCellSource('logs')
+ const second = createDefaultCellSource('logs')
+
+ expect(cellSourceSchema.parse(first)).toEqual({
+ id: 'logs',
+ type: 'logs',
+ parameters: {
+ time_range: { type: 'relative', amount: 1, unit: 'hour' },
+ },
+ })
+ expect(first.parameters.time_range).not.toBe(second.parameters.time_range)
+ expect(cellSourceSchema.parse(createDefaultCellSource('database'))).toEqual({
+ id: 'database',
+ type: 'database',
+ parameters: {},
+ })
+ })
+
+ it('rejects parameters that do not match the selected source type', () => {
+ expect(() =>
+ cellSourceSchema.parse({
+ id: 'logs',
+ type: 'logs',
+ parameters: { identifier: 'replica-1' },
+ })
+ ).toThrow()
+
+ expect(() =>
+ cellSourceSchema.parse({
+ id: 'database',
+ type: 'database',
+ parameters: { time_range: { type: 'relative', amount: 1, unit: 'hour' } },
+ })
+ ).toThrow()
+
+ expect(() =>
+ cellSourceSchema.parse({
+ id: 'logs',
+ type: 'logs',
+ parameters: { time_range: { type: 'relative', amount: 2, unit: 'week' } },
+ })
+ ).toThrow()
+ })
+
+ it('rejects absolute ranges that do not move forward in time', () => {
+ expect(
+ logTimeRangeSchema.safeParse({
+ type: 'absolute',
+ from: '2025-01-01T00:00:00.000Z',
+ to: '2025-01-02T00:00:00.000Z',
+ }).success
+ ).toBe(true)
+
+ const equal = logTimeRangeSchema.safeParse({
+ type: 'absolute',
+ from: '2025-01-01T00:00:00.000Z',
+ to: '2025-01-01T00:00:00.000Z',
+ })
+ expect(equal.success).toBe(false)
+ expect(equal.error?.issues[0].path).toEqual(['to'])
+
+ expect(
+ logTimeRangeSchema.safeParse({
+ type: 'absolute',
+ from: '2025-01-02T00:00:00.000Z',
+ to: '2025-01-01T00:00:00.000Z',
+ }).success
+ ).toBe(false)
+
+ expect(() =>
+ cellSourceSchema.parse({
+ id: 'logs',
+ type: 'logs',
+ parameters: {
+ time_range: {
+ type: 'absolute',
+ from: '2025-01-02T00:00:00.000Z',
+ to: '2025-01-01T00:00:00.000Z',
+ },
+ },
+ })
+ ).toThrow()
+ })
+
+ it('reports an invalid endpoint against its own field rather than the ordering rule', () => {
+ const result = logTimeRangeSchema.safeParse({
+ type: 'absolute',
+ from: 'not-a-date',
+ to: '2025-01-01T00:00:00.000Z',
+ })
+
+ expect(result.success).toBe(false)
+ expect(result.error?.issues).toHaveLength(1)
+ expect(result.error?.issues[0].path).toEqual(['from'])
+ })
+})
diff --git a/apps/studio/data/query-sources/query-source-registry.ts b/apps/studio/data/query-sources/query-source-registry.ts
new file mode 100644
index 0000000000000..eb8124a4f5830
--- /dev/null
+++ b/apps/studio/data/query-sources/query-source-registry.ts
@@ -0,0 +1,152 @@
+import dayjs from 'dayjs'
+import * as z from 'zod'
+
+import { logsAllEndpointUrl } from '@/data/logs/logs-endpoint'
+import { isoDateTimeString } from '@/lib/iso-datetime'
+
+export type LogTimeRange =
+ | {
+ type: 'relative'
+ amount: number
+ unit: 'minute' | 'hour' | 'day'
+ }
+ | {
+ type: 'absolute'
+ from: string
+ to: string
+ }
+
+export type DatabaseSource = {
+ id: 'database'
+ type: 'database'
+ endpoint: '/platform/pg-meta/{ref}/query'
+ parameters: {
+ /**
+ * Query-owned database selection. The SQL editor still adapts its legacy
+ * global/local-storage selector into this shape; new consumers persist the
+ * identifier directly with their query.
+ */
+ identifier?: string
+ }
+}
+
+export type LogsSource = {
+ id: 'logs'
+ type: 'logs'
+ endpoint: ReturnType
+ parameters: {
+ time_range: LogTimeRange
+ }
+}
+
+/** Sources are registered by Studio; query surfaces only store a source binding. */
+export type Source = DatabaseSource | LogsSource
+
+export type CellSourceOf = Pick
+
+export type CellSource = CellSourceOf | CellSourceOf
+
+export const DEFAULT_LOG_TIME_RANGE: LogTimeRange = {
+ type: 'relative',
+ amount: 1,
+ unit: 'hour',
+}
+
+export const QUERY_SOURCE_REGISTRY = {
+ database: {
+ id: 'database',
+ type: 'database',
+ endpoint: '/platform/pg-meta/{ref}/query',
+ parameters: {},
+ },
+ logs: {
+ id: 'logs',
+ type: 'logs',
+ endpoint: logsAllEndpointUrl(true),
+ parameters: { time_range: DEFAULT_LOG_TIME_RANGE },
+ },
+} as const satisfies Record
+
+export type QuerySourceId = keyof typeof QUERY_SOURCE_REGISTRY
+
+export const QUERY_SOURCES = Object.values(QUERY_SOURCE_REGISTRY) satisfies Source[]
+
+export const QUERY_SOURCE_LABELS: Record = {
+ database: 'Database',
+ logs: 'Logs',
+}
+
+const isoDateTimeSchema = z.string().refine((value) => isoDateTimeString(value) !== null, {
+ message: 'must be a valid ISO-8601 datetime',
+})
+
+export const logTimeRangeSchema = z
+ .discriminatedUnion('type', [
+ z
+ .object({
+ type: z.literal('relative'),
+ amount: z.number().int().positive(),
+ unit: z.enum(['minute', 'hour', 'day']),
+ })
+ .strict(),
+ z
+ .object({
+ type: z.literal('absolute'),
+ from: isoDateTimeSchema,
+ to: isoDateTimeSchema,
+ })
+ .strict(),
+ ])
+ .refine(
+ (range) => {
+ if (range.type !== 'absolute') return true
+
+ const from = dayjs(range.from)
+ const to = dayjs(range.to)
+ // An unparseable endpoint is already reported against its own field; the
+ // ordering rule stays quiet so it doesn't add a second, misleading issue.
+ if (!from.isValid() || !to.isValid()) return true
+
+ return to.isAfter(from)
+ },
+ {
+ message: 'must be later than the start of the range',
+ path: ['to'],
+ }
+ )
+
+export const cellSourceSchema = z.discriminatedUnion('type', [
+ z
+ .object({
+ id: z.literal('database'),
+ type: z.literal('database'),
+ parameters: z.object({ identifier: z.string().optional() }).strict(),
+ })
+ .strict(),
+ z
+ .object({
+ id: z.literal('logs'),
+ type: z.literal('logs'),
+ parameters: z.object({ time_range: logTimeRangeSchema }).strict(),
+ })
+ .strict(),
+])
+
+export function createDefaultCellSource(id: 'database'): CellSourceOf
+export function createDefaultCellSource(id: 'logs'): CellSourceOf
+export function createDefaultCellSource(id: QuerySourceId): CellSource
+export function createDefaultCellSource(id: QuerySourceId): CellSource {
+ const source = QUERY_SOURCE_REGISTRY[id]
+
+ if (source.type === 'logs') {
+ return {
+ id: source.id,
+ type: source.type,
+ parameters: { time_range: { ...source.parameters.time_range } },
+ }
+ }
+
+ return { id: source.id, type: source.type, parameters: { ...source.parameters } }
+}
+
+export const getQuerySource = (id: QuerySourceId): Source => QUERY_SOURCE_REGISTRY[id]
diff --git a/apps/studio/data/sql/execute-sql-mutation.ts b/apps/studio/data/sql/execute-sql-mutation.ts
index 3718fac1f5996..d1c2122cbf6af 100644
--- a/apps/studio/data/sql/execute-sql-mutation.ts
+++ b/apps/studio/data/sql/execute-sql-mutation.ts
@@ -12,6 +12,7 @@ import {
createNodeTree,
} from '@/components/interfaces/ExplainVisualizer/ExplainVisualizer.parser'
import { handleError as handleErrorFetchers, post } from '@/data/fetchers'
+import { QUERY_SOURCE_REGISTRY } from '@/data/query-sources/query-source-registry'
import { MB } from '@/lib/constants'
import { sqlEventParser } from '@/lib/sql-event-parser'
import { useTrack } from '@/lib/telemetry/track'
@@ -159,7 +160,7 @@ export async function executeSql(
const key =
queryKey?.filter((seg) => typeof seg === 'string' || typeof seg === 'number').join('-') ?? ''
- const result = await post('/platform/pg-meta/{ref}/query', {
+ const result = await post(QUERY_SOURCE_REGISTRY.database.endpoint, {
...options,
body: { query: sql, disable_statement_timeout: isStatementTimeoutDisabled },
params: {
diff --git a/apps/studio/state/sql-editor/sql-editor-session-state.ts b/apps/studio/state/sql-editor/sql-editor-session-state.ts
index 38aeafc030c19..b7813f58333ab 100644
--- a/apps/studio/state/sql-editor/sql-editor-session-state.ts
+++ b/apps/studio/state/sql-editor/sql-editor-session-state.ts
@@ -1,6 +1,6 @@
import { proxy, ref, snapshot, useSnapshot } from 'valtio'
-import type { LogDateRange } from '@/components/interfaces/SQLEditor/querySource'
+import type { LogTimeRange } from '@/data/query-sources/query-source-registry'
/**
* Ephemeral, per-session SQL editor state that is NOT persisted: query results,
@@ -35,11 +35,11 @@ export const sqlEditorSessionState = proxy({
* The logs time range for a logs snippet, keyed by snippet id. Session state —
* never written to snippet content — so it works on read-only shared snippets
* and resets on reload. An unset snippet has no entry; read sites fall back to
- * `DEFAULT_LOG_DATE_RANGE`.
+ * `DEFAULT_LOG_TIME_RANGE`.
*/
- logRange: {} as { [snippetId: string]: LogDateRange },
+ logRange: {} as { [snippetId: string]: LogTimeRange },
- setLogRange: (id: string, range: LogDateRange) => {
+ setLogRange: (id: string, range: LogTimeRange) => {
sqlEditorSessionState.logRange[id] = range
},
diff --git a/apps/studio/tests/components/SQLEditor/QuerySourceMenu.test.tsx b/apps/studio/tests/components/SQLEditor/QuerySourceMenu.test.tsx
index 6985f0ad82202..d1ef963eb6342 100644
--- a/apps/studio/tests/components/SQLEditor/QuerySourceMenu.test.tsx
+++ b/apps/studio/tests/components/SQLEditor/QuerySourceMenu.test.tsx
@@ -1,42 +1,58 @@
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { mockAnimationsApi } from 'jsdom-testing-mocks'
-import { describe, expect, it } from 'vitest'
+import { beforeEach, describe, expect, it } from 'vitest'
-import { DEFAULT_LOG_DATE_RANGE } from '@/components/interfaces/SQLEditor/querySource'
import { QuerySourceMenu } from '@/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu'
+import { DEFAULT_LOG_TIME_RANGE } from '@/data/query-sources/query-source-registry'
import { customRender } from '@/tests/lib/custom-render'
import { addAPIMock } from '@/tests/lib/msw'
// QuerySourceMenu renders a Radix dropdown (+ nested dialog), both of which use Web Animations.
mockAnimationsApi()
-addAPIMock({
- method: 'get',
- path: '/platform/projects/:ref',
- response: {
- id: 1,
- ref: 'default',
- organization_id: 1,
- name: 'Test Project',
- status: 'ACTIVE_HEALTHY',
- cloud_provider: 'AWS',
- region: 'us-east-1',
- db_host: 'db.default.supabase.co',
- restUrl: 'https://default.supabase.co/rest/v1/',
- inserted_at: '2024-01-01T00:00:00Z',
- updated_at: '2024-01-01T00:00:00Z',
- subscription_id: 'sub_123',
- is_branch_enabled: false,
- is_physical_backups_enabled: false,
- high_availability: false,
- integration_source: null,
- connectionString: 'postgresql://postgres@localhost:5432/postgres',
- is_hibernating: false,
- },
+beforeEach(() => {
+ addAPIMock({
+ method: 'get',
+ path: '/platform/projects/:ref',
+ response: {
+ id: 1,
+ ref: 'default',
+ organization_id: 1,
+ name: 'Test Project',
+ status: 'ACTIVE_HEALTHY',
+ cloud_provider: 'AWS',
+ region: 'us-east-1',
+ db_host: 'db.default.supabase.co',
+ restUrl: 'https://default.supabase.co/rest/v1/',
+ inserted_at: '2024-01-01T00:00:00Z',
+ updated_at: '2024-01-01T00:00:00Z',
+ subscription_id: 'sub_123',
+ is_branch_enabled: false,
+ is_physical_backups_enabled: false,
+ high_availability: false,
+ integration_source: null,
+ connectionString: 'postgresql://postgres@localhost:5432/postgres',
+ is_hibernating: false,
+ },
+ })
})
describe('QuerySourceMenu', () => {
+ it('hides logs when creating logs queries is unavailable', async () => {
+ customRender(
+
+ )
+
+ await userEvent.click(screen.getByRole('button', { name: 'Query source: Database' }))
+
+ expect(screen.queryByText('Logs')).not.toBeInTheDocument()
+ })
+
it('keeps the dropdown open across a source switch, so the new source’s controls appear without reopening it', async () => {
// Selecting a source doesn't mutate `runSource` in place — it navigates to a
// fresh tab, and the parent re-renders this component with the new source once
@@ -57,7 +73,7 @@ describe('QuerySourceMenu', () => {
rerender(
)
diff --git a/apps/studio/tests/features/logs/Logs.Datepickers.test.tsx b/apps/studio/tests/features/logs/Logs.Datepickers.test.tsx
index 09e328d5f4ec5..c9bff95574f13 100644
--- a/apps/studio/tests/features/logs/Logs.Datepickers.test.tsx
+++ b/apps/studio/tests/features/logs/Logs.Datepickers.test.tsx
@@ -96,7 +96,7 @@ describe('generateDynamicHelper', () => {
})
describe('generateDynamicHelpers', () => {
- test('generates 3 helpers for minutes, hours, days', () => {
+ test('generates helpers for every supported relative unit', () => {
const helpers = generateDynamicHelpers(5)
expect(helpers).toHaveLength(3)
expect(helpers[0].text).toBe('Last 5 minutes')
@@ -112,7 +112,7 @@ describe('generateHelpersFromInput', () => {
expect(generateHelpersFromInput('2yoie')).toBeNull()
})
- test('returns 3 helpers for number only input', () => {
+ test('returns a helper for every unit for number only input', () => {
const helpers = generateHelpersFromInput('25')
expect(helpers).toHaveLength(3)
expect(helpers![0].text).toBe('Last 25 minutes')