diff --git a/api/generated/api.bundled.json b/api/generated/api.bundled.json new file mode 100644 index 0000000..e9d81e5 --- /dev/null +++ b/api/generated/api.bundled.json @@ -0,0 +1,12369 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Ampersand public API", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://api.withampersand.com/v1" + } + ], + "paths": { + "/oauth-connect": { + "post": { + "operationId": "oauthConnect", + "summary": "Generate OAuth authorization URL", + "description": "Generate a URL for the browser to render to kick off OAuth flow. You can use this endpoint as an alternative to the [prebuilt UI components](https://docs.withampersand.com/embeddable-ui-components).", + "tags": [ + "OAuth" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "projectIdOrName", + "groupRef", + "consumerRef", + "provider" + ], + "properties": { + "projectIdOrName": { + "type": "string", + "description": "The Ampersand project ID or project name.", + "example": "my-project" + }, + "provider": { + "type": "string", + "description": "The provider that this app connects to.", + "example": "salesforce" + }, + "groupRef": { + "type": "string", + "description": "Your application's identifier for the organization or workspace that this connection belongs to (e.g. an org ID or team ID).", + "example": "group-123" + }, + "groupName": { + "type": "string", + "description": "The display name for the group. Defaults to groupRef if not provided.", + "example": "Organization Name" + }, + "consumerRef": { + "type": "string", + "description": "The ID that your app uses to identify the user whose SaaS credential will be used for this OAuth flow.", + "example": "user_123456" + }, + "consumerName": { + "type": "string", + "description": "The display name for the consumer. Defaults to consumerRef if not provided.", + "example": "John Doe" + }, + "providerWorkspaceRef": { + "type": "string", + "description": "The identifier for the provider workspace (e.g. the Salesforce subdomain).", + "example": "acme-corp" + }, + "providerMetadata": { + "description": "Additional provider-specific metadata required by certain providers (e.g., account ID for NetSuite). See provider documentation for which fields are needed.", + "$ref": "#/components/schemas/ProviderMetadata", + "example": { + "accountId": { + "value": "1234567890", + "source": "input" + } + } + }, + "providerAppId": { + "type": "string", + "description": "ID of the provider app, returned from the [Create Provider App endpoint](https://docs.withampersand.com/reference/provider-apps/create-provider-app). If omitted, the default provider app that was set up on the Ampersand Dashboard is assumed.", + "example": "32356abe-d2fd-49c7-9030-abdcbc6456d4" + }, + "enableCSRFProtection": { + "type": "boolean", + "description": "This boolean flag is used by the UI library internally. Set it to false or omit it when manually calling this API.", + "example": false + } + } + }, + "examples": { + "basicOAuth": { + "summary": "Basic OAuth flow (required fields only)", + "value": { + "projectIdOrName": "my-project", + "provider": "salesforce", + "groupRef": "group-123", + "consumerRef": "user_123456" + } + }, + "withProviderWorkspace": { + "summary": "With provider workspace and provider app", + "value": { + "projectIdOrName": "my-project", + "provider": "salesforce", + "groupRef": "group-123", + "groupName": "Acme Corp", + "consumerRef": "user_123456", + "consumerName": "John Doe", + "providerWorkspaceRef": "acme-corp", + "providerAppId": "32356abe-d2fd-49c7-9030-abdcbc6456d4" + } + }, + "withProviderMetadata": { + "summary": "With provider metadata (e.g. NetSuite account ID)", + "value": { + "projectIdOrName": "my-project", + "provider": "netsuite", + "groupRef": "group-456", + "consumerRef": "user_789012", + "providerMetadata": { + "accountId": { + "value": "1234567890", + "source": "input" + } + } + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "URL to render", + "example": "https://login.salesforce.com/services/oauth2/authorize?client_id=xxx&redirect_uri=https%3A%2F%2Fapi.withampersand.com%2Fcallbacks%2Fv1%2Foauth&state=xxx" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "connectOAuthParams" + } + }, + "/projects/{projectIdOrName}/connections/{connectionId}:oauth-update": { + "patch": { + "operationId": "oauthUpdate", + "summary": "Generate OAuth authorization URL for existing connection", + "description": "Generate a URL for the browser to render to kick off an OAuth flow that updates an existing connection. Use this when the connection's credentials need to be refreshed. To start an OAuth flow without specifying a connection ID, use the [/oauth-connect endpoint](https://docs.withampersand.com/reference/oauth/generate-oauth-authorization-url) instead.\n", + "tags": [ + "OAuth" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Ampersand project ID or name." + }, + { + "name": "connectionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The ID of the connection to update." + } + ], + "responses": { + "200": { + "description": "URL to initiate OAuth flow", + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "https://login.salesforce.com/services/oauth2/authorize?client_id=xxx&redirect_uri=https%3A%2F%2Fapi.withampersand.com%2Fcallbacks%2Fv1%2Foauth&state=xxx" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects": { + "get": { + "summary": "List projects", + "description": "Lists projects your credentials can access.", + "operationId": "listProjects", + "tags": [ + "Project" + ], + "responses": { + "200": { + "description": "List of projects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Project" + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "post": { + "summary": "Create a new project", + "description": "Creates a new project within an organization. A project is a container for provider apps, integrations, and connections.", + "operationId": "createProject", + "tags": [ + "Project" + ], + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "appName", + "name", + "orgId" + ], + "type": "object", + "properties": { + "appName": { + "type": "string", + "description": "The display name of your application, shown to end users during the connection flow.", + "minLength": 1, + "maxLength": 128, + "example": "MailMonkey" + }, + "name": { + "type": "string", + "description": "The unique name for the project. Must contain only letters, numbers, and hyphens. Values are normalized to lowercase on save.", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$", + "minLength": 2, + "maxLength": 128, + "example": "mailmonkey-staging" + }, + "orgId": { + "type": "string", + "description": "The ID of the organization this project belongs to. Obtain this from the Ampersand Dashboard or by calling `GET /orgs`.", + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + } + }, + "example": { + "appName": "MailMonkey", + "name": "mailmonkey-staging", + "orgId": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The newly created project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + }, + "422": { + "description": "Unprocessable Entity — the request body failed validation (e.g. invalid characters in project name, missing required fields).", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "project" + } + }, + "/projects/{projectIdOrName}": { + "get": { + "summary": "Get a project", + "description": "Get a project by its ID or name.", + "operationId": "getProject", + "tags": [ + "Project" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "includeEntitlements", + "in": "query", + "required": false, + "description": "If true, the response includes the project's entitlements (plan-based feature flags). Defaults to false.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "The requested project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "patch": { + "summary": "Update a project", + "operationId": "updateProject", + "description": "Update a project's mutable fields using field masks. Currently, the updatable fields are `appName` (the display name shown to end users) and `name` (the unique project identifier).", + "tags": [ + "Project" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "project", + "updateMask" + ], + "type": "object", + "properties": { + "updateMask": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field paths specifying which fields to update. Each path must have a\ncorresponding value in the `project` object. A field included in `project` but\nnot listed here will be ignored. Allowed values:\n- `appName` - the display name of the application, shown to end users during the connection flow.\n- `name` - the unique project identifier (must be unique within your organization).\n", + "example": [ + "appName" + ] + }, + "project": { + "type": "object", + "properties": { + "appName": { + "type": "string", + "description": "The display name of the application, shown to end users during the connection flow.", + "example": "MailMonkey" + }, + "name": { + "type": "string", + "description": "The unique name for the project. Must be unique within the organization.", + "example": "mailmonkey-staging" + } + }, + "description": "The project fields to update. Only fields whose paths are listed in `updateMask`\nwill be applied; all other fields in this object are ignored.\n" + } + } + }, + "example": { + "updateMask": [ + "appName" + ], + "project": { + "appName": "MailMonkey Pro" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The updated project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "projectUpdate" + } + }, + "/projects/{projectIdOrName}/provider-apps": { + "get": { + "summary": "List provider apps", + "operationId": "listProviderApps", + "tags": [ + "Provider App" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "TThe Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "responses": { + "200": { + "description": "List of provider apps", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderApp" + } + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "post": { + "summary": "Create a new provider app", + "operationId": "createProviderApp", + "tags": [ + "Provider App" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "clientId", + "clientSecret", + "provider" + ], + "type": "object", + "properties": { + "externalRef": { + "type": "string", + "description": "The ID used by the provider to identify the app (optional).", + "example": "external-id-123" + }, + "provider": { + "type": "string", + "description": "The SaaS provider that this app connects to.", + "example": "salesforce" + }, + "clientId": { + "type": "string", + "description": "The OAuth client ID for this app.", + "example": "client-id-123" + }, + "clientSecret": { + "type": "string", + "description": "The OAuth client secret for this app.", + "example": "client-secret-123" + }, + "scopes": { + "type": "array", + "description": "The OAuth scopes for this app.", + "items": { + "type": "string", + "example": [ + "read", + "write" + ] + } + }, + "metadata": { + "$ref": "#/components/schemas/ProviderAppMetadata" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The newly created provider app", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderApp" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "providerApp" + } + }, + "/projects/{projectIdOrName}/provider-apps/{providerAppId}": { + "delete": { + "summary": "Delete a provider app.", + "operationId": "deleteProviderApp", + "tags": [ + "Provider App" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "providerAppId", + "in": "path", + "required": true, + "description": "ID of the provider app, returned by the CreateProviderApp call.", + "schema": { + "type": "string" + }, + "example": "32356abe-d2fd-49c7-9030-abdcbc6456d4" + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "patch": { + "summary": "Update a provider app", + "operationId": "updateProviderApp", + "tags": [ + "Provider App" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "providerAppId", + "in": "path", + "required": true, + "description": "ID of the provider app, returned by the CreateProviderApp call.", + "schema": { + "type": "string" + }, + "example": "32356abe-d2fd-49c7-9030-abdcbc6456d4" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "providerApp", + "updateMask" + ], + "type": "object", + "properties": { + "updateMask": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field paths specifying which fields to update. Allowed values include:\n- externalRef\n- clientId\n- clientSecret\n- provider\n- scopes\n- metadata\n", + "example": [ + "externalRef", + "clientId" + ] + }, + "providerApp": { + "type": "object", + "properties": { + "externalRef": { + "type": "string", + "description": "The ID used by the provider to identify the app (optional).", + "example": "external-id-123" + }, + "provider": { + "type": "string", + "description": "The SaaS provider that this app connects to.", + "example": "salesforce" + }, + "clientId": { + "type": "string", + "description": "The OAuth client ID for this app.", + "example": "client-id-123" + }, + "clientSecret": { + "type": "string", + "description": "The OAuth client secret for this app.", + "example": "client-secret-123" + }, + "scopes": { + "type": "array", + "description": "The OAuth scopes for this app.", + "items": { + "type": "string", + "example": [ + "read", + "write" + ] + } + }, + "metadata": { + "$ref": "#/components/schemas/ProviderAppMetadata" + } + }, + "description": "The provider app fields to update. (Only include the fields you'd like to update.)" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The updated provider app", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderApp" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "providerAppUpdate" + } + }, + "/projects/{projectIdOrName}/integrations": { + "get": { + "summary": "List integrations", + "operationId": "listIntegrations", + "tags": [ + "Integration" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "responses": { + "200": { + "description": "List of integrations", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Integration" + } + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "post": { + "summary": "Create a new integration.", + "operationId": "createIntegration", + "tags": [ + "Integration" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "name", + "provider", + "latestRevision" + ], + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The integration name.", + "example": "my-integration" + }, + "provider": { + "type": "string", + "description": "The provider name (e.g. \"salesforce\", \"hubspot\")" + }, + "latestRevision": { + "type": "object", + "required": [ + "content", + "specVersion" + ], + "properties": { + "specVersion": { + "type": "string", + "description": "The spec version string.", + "example": "1.0.0" + }, + "content": { + "$ref": "#/components/schemas/Integration-2" + } + } + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": {} + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "integration" + } + }, + "/projects/{projectIdOrName}/integrations/{integrationIdOrName}": { + "get": { + "summary": "Get an integration by ID or name", + "operationId": "getIntegration", + "tags": [ + "Integration" + ], + "parameters": [ + { + "name": "integrationIdOrName", + "in": "path", + "required": true, + "description": "The integration ID or name.", + "schema": { + "type": "string" + }, + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "responses": { + "200": { + "description": "The integration", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Integration" + } + } + } + }, + "404": { + "description": "Integration not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "delete": { + "summary": "Delete an integration", + "operationId": "deleteIntegration", + "description": "Delete an integration and all its installations.", + "tags": [ + "Integration" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationIdOrName", + "in": "path", + "required": true, + "description": "The integration ID or name.", + "schema": { + "type": "string" + }, + "example": "123e4567-e89b-12d3-a456-426614174000" + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "404": { + "description": "Integration not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/integrations:batch": { + "put": { + "summary": "Batch upsert a group of integrations", + "operationId": "batchUpsertIntegrations", + "description": "This endpoint is used by the Ampersand CLI to batch upsert integrations. We recommend using the [CLI's deploy command](https://docs.withampersand.com/cli/overview#deploy-integrations) rather than this API endpoint directly.", + "tags": [ + "Integration" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "destructive", + "in": "query", + "required": false, + "description": "Defaults to false. This flag controls whether to perform destructive actions when deploying integrations, like pausing all read actions for an object that was removed in the latest revision.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sourceZipUrl": { + "type": "string", + "description": "URL of where a zip of the source files can be downloaded (e.g. Google Cloud Storage URL).", + "example": "https://storage.googleapis.com/my-bucket/source-files/integration-v1.2.3.zip" + }, + "sourceYaml": { + "type": "string", + "description": "A YAML string that defines the integrations." + } + }, + "description": "The source of the integrations to upsert. One of sourceZipUrl or sourceYaml is required." + } + } + } + }, + "responses": { + "200": { + "description": "Upserted integrations.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Integration" + } + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/revisions": { + "post": { + "summary": "Create a new revision.", + "operationId": "createRevision", + "description": "We recommend using the [CLI's deploy command](https://docs.withampersand.com/cli/overview#deploy-integrations) rather than this API endpoint directly, unless you have an advanced use case.", + "tags": [ + "Revision" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The integration ID.", + "schema": { + "type": "string" + } + }, + { + "name": "destructive", + "in": "query", + "required": false, + "description": "Defaults to false. This flag controls whether to perform destructive actions when deploying integrations, like pausing all read actions for an object that was removed in the latest revision.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sourceZipUrl": { + "type": "string", + "description": "URL of where a zip of the source files can be downloaded (e.g. Google Cloud Storage URL).", + "example": "https://storage.googleapis.com/my-bucket/source-files/integration-v1.2.3.zip" + }, + "sourceYaml": { + "type": "string", + "description": "The source YAML file that defines the revision." + } + }, + "description": "The source of the revision to create. One of sourceZipUrl or sourceYaml is required." + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": {} + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "revision" + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/revisions/{revisionId}:hydrate": { + "get": { + "summary": "Get a hydrated revision", + "description": "Returns the integration revision enriched with live field metadata from the consumer's connected SaaS instance, such as available fields, display names, and type for each object defined in the integration.\n", + "operationId": "getHydratedRevision", + "tags": [ + "Revision" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The integration ID.", + "schema": { + "type": "string" + }, + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + { + "name": "revisionId", + "in": "path", + "required": true, + "description": "The revision ID. You can find this on the integration object's `latestRevision.id` field.", + "schema": { + "type": "string" + }, + "example": "f0e1d2c3-b4a5-6789-0abc-def123456789" + }, + { + "name": "connectionId", + "in": "query", + "required": true, + "description": "The ID of the consumer's connection to the SaaS provider. This connection's credentials are used to fetch field metadata from the provider's API.", + "schema": { + "type": "string" + }, + "example": "1a2b3c4d-5e6f-7890-abcd-ef0123456789" + } + ], + "responses": { + "200": { + "description": "Hydrated revision.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HydratedRevision" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/installations": { + "get": { + "summary": "List installations for an integration", + "description": "Lists all installations for a specific integration within a project. To list installations across all integrations, use listInstallationsForProject instead.\n", + "operationId": "listInstallations", + "tags": [ + "Installation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The unique identifier (UUID) of the integration.", + "schema": { + "type": "string" + }, + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + { + "name": "groupRef", + "in": "query", + "description": "The ID that your app uses to identify a group of users (e.g. an org ID, workspace ID, or team ID). When provided, only returns installations belonging to this group.", + "example": "group-123", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of installations", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Installation" + } + }, + "example": [ + { + "id": "3f8b2a1e-7c4d-4e9a-b5f6-1d2e3a4b5c6d", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "integrationId": "550e8400-e29b-41d4-a716-446655440000", + "group": { + "groupRef": "org_12345", + "groupName": "Acme Corp", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "healthStatus": "healthy", + "connection": { + "id": "9d8c7b6a-5e4f-3a2b-1c0d-ef9876543210", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "provider": "salesforce", + "group": { + "groupRef": "org_12345", + "groupName": "Acme Corp", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "consumer": { + "consumerRef": "user_67890", + "consumerName": "Jane Smith", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "createTime": "2024-01-15T10:30:00.000000Z", + "authScheme": "oauth2/authorizationCode", + "status": "working" + }, + "createTime": "2024-01-15T10:30:00.000000Z", + "createdBy": "consumer:user_67890", + "config": { + "id": "e4d3c2b1-a098-7654-3210-fedcba987654", + "revisionId": "f0e1d2c3-b4a5-6789-0abc-def123456789", + "createTime": "2024-01-15T10:30:00.000000Z", + "createdBy": "consumer:user_67890", + "content": { + "provider": "salesforce", + "read": { + "objects": { + "account": { + "objectName": "account", + "schedule": "*/15 * * * *", + "destination": "accountWebhook", + "selectedFields": { + "name": true, + "industry": true + } + } + } + } + } + } + } + ] + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "post": { + "summary": "Create a new installation", + "operationId": "createInstallation", + "description": "Install an integration for a specific group. The group must already have a SaaS connection — either provide its `connectionId`, or omit it to use the group's default. To create a connection, use the [OAuth Connect endpoint](https://docs.withampersand.com/reference/oauth/generate-oauth-authorization-url) or the [prebuilt UI components](https://docs.withampersand.com/embeddable-ui-components).\n", + "tags": [ + "Installation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The integration ID.", + "schema": { + "type": "string" + }, + "example": "113e9685-9a51-42cc-8662-9d9725b17f14" + }, + { + "name": "skipSampling", + "in": "query", + "required": false, + "description": "When `true`, skips the sample read that validates the installation's read configuration against the provider before saving. Defaults to `false`.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "config", + "groupRef" + ], + "type": "object", + "properties": { + "groupRef": { + "type": "string", + "description": "The ID of the user group that has access to this installation.", + "example": "group-123" + }, + "connectionId": { + "type": "string", + "description": "The ID of the SaaS connection tied to this installation. If omitted the default connection for this group will be used.", + "example": "a1c4e7b2-8f3d-4a6e-9c2b-5d8f1e4a7b3c" + }, + "config": { + "required": [ + "content" + ], + "type": "object", + "properties": { + "revisionId": { + "type": "string", + "deprecated": true, + "description": "Deprecated: This field will be automatically set to the latest revision." + }, + "createdBy": { + "type": "string", + "description": "The person who created the config, in the format of \"consumer:{consumer-id}\", \"builder:{builder-id}\", or \"api:{api-caller}\".", + "default": "api:create-installation" + }, + "content": { + "$ref": "#/components/schemas/ConfigContent", + "description": "The content of the config." + } + }, + "description": "The config of the installation." + } + } + }, + "examples": { + "writeOnly": { + "summary": "Minimal write-only installation", + "value": { + "groupRef": "group-123", + "connectionId": "a1c4e7b2-8f3d-4a6e-9c2b-5d8f1e4a7b3c", + "config": { + "content": { + "provider": "salesforce", + "write": { + "objects": { + "contacts": { + "objectName": "contacts" + } + } + } + } + } + } + }, + "readWriteAndSubscribe": { + "summary": "Read, write, and subscribe", + "value": { + "groupRef": "group-456", + "connectionId": "b2d5f8a3-9e4c-4b7f-8d1a-6c9e2f5b8d4a", + "config": { + "content": { + "provider": "salesforce", + "read": { + "objects": { + "contacts": { + "objectName": "contacts", + "schedule": "*/15 * * * *", + "selectedFields": { + "phone": true, + "email": true + }, + "selectedFieldMappings": { + "phoneNumber": "phone", + "emailAddress": "email" + } + } + } + }, + "write": { + "objects": { + "contacts": { + "objectName": "contacts" + } + } + }, + "subscribe": { + "objects": { + "contacts": { + "objectName": "contacts", + "destination": "contactWebhook", + "inheritFieldsAndMappings": true + } + } + } + } + } + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity. Returned when the config is invalid, or when the sample read fails because a selected field or mapping is not visible to the connected user.", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "installation" + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/installations/{installationId}": { + "get": { + "summary": "Get an installation", + "description": "Retrieves a single installation by ID, including its connection details, config, and health status.\n", + "operationId": "getInstallation", + "tags": [ + "Installation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The unique identifier (UUID) of the integration.", + "schema": { + "type": "string" + }, + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + { + "name": "installationId", + "in": "path", + "required": true, + "description": "The unique identifier (UUID) of the installation.", + "schema": { + "type": "string" + }, + "example": "7b3c9d2e-5a1f-4e8b-b6d4-9c8a2f1e5d3b" + } + ], + "responses": { + "200": { + "description": "The installation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + }, + "example": { + "id": "3f8b2a1e-7c4d-4e9a-b5f6-1d2e3a4b5c6d", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "integrationId": "550e8400-e29b-41d4-a716-446655440000", + "group": { + "groupRef": "org_12345", + "groupName": "Acme Corp", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "healthStatus": "healthy", + "connection": { + "id": "9d8c7b6a-5e4f-3a2b-1c0d-ef9876543210", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "provider": "salesforce", + "group": { + "groupRef": "org_12345", + "groupName": "Acme Corp", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "consumer": { + "consumerRef": "user_67890", + "consumerName": "Jane Smith", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "createTime": "2024-01-15T10:30:00.000000Z", + "authScheme": "oauth2/authorizationCode", + "status": "working" + }, + "createTime": "2024-01-15T10:30:00.000000Z", + "createdBy": "consumer:user_67890", + "config": { + "id": "e4d3c2b1-a098-7654-3210-fedcba987654", + "revisionId": "f0e1d2c3-b4a5-6789-0abc-def123456789", + "createTime": "2024-01-15T10:30:00.000000Z", + "createdBy": "consumer:user_67890", + "content": { + "provider": "salesforce", + "read": { + "objects": { + "account": { + "objectName": "account", + "schedule": "*/15 * * * *", + "destination": "accountWebhook", + "selectedFields": { + "name": true, + "industry": true + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "delete": { + "summary": "Delete an installation", + "operationId": "deleteInstallation", + "tags": [ + "Installation" + ], + "description": "Delete an Installation. This will also delete the associated Connection if it is not used by any other Installations.\n", + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The integration ID.", + "schema": { + "type": "string" + } + }, + { + "name": "installationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The Ampersand installation ID." + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "patch": { + "summary": "Update an installation", + "operationId": "updateInstallation", + "tags": [ + "Installation" + ], + "description": "Update an installation using field masks. Note: subscribe config changes trigger a subscription change in the provider's system, which typically takes 1-2 minutes but may take up to 10 minutes.\n", + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The ID of the integration that this installation belongs to.", + "schema": { + "type": "string" + }, + "example": "e3a7f9c1-4b2d-4e8a-9f6b-2d5c8a1e3b7f" + }, + { + "name": "installationId", + "in": "path", + "required": true, + "description": "The Ampersand installation ID.", + "schema": { + "type": "string" + }, + "example": "7b3c9d2e-5a1f-4e8b-b6d4-9c8a2f1e5d3b" + }, + { + "name": "skipSampling", + "in": "query", + "required": false, + "description": "When `true`, skips the sample read that validates the installation's read configuration against the provider before saving. Defaults to `false`.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "installation", + "updateMask" + ], + "type": "object", + "properties": { + "updateMask": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field paths specifying which fields to update. Each path must have a corresponding value in the `installation` object. A field included in `installation` but not listed here will be ignored. Allowed values:\n- `connectionId` - switch the SaaS connection tied to this installation.\n- `config.createdBy` - change the attribution for who created this config.\n- `config.content.read.objects.` - replace the read config for a single object (e.g. `config.content.read.objects.contacts`).\n- `config.content.write.objects.` - replace the write config for a single object.\n- `config.content.write.objects` - replace the entire write objects map.\n- `config.content.subscribe.objects.` - replace the subscribe config for a single object.\n- `config.content.subscribe.objects` - replace the entire subscribe objects map.\n- `config.content.proxy.enabled` - enable or disable the proxy.\n\nReplace `` with the provider object name (e.g. `contacts`, `leads`, `accounts`).\n", + "example": [ + "config.content.read.objects.contacts", + "config.content.write.objects.leads" + ] + }, + "installation": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "description": "The ID of the SaaS connection tied to this installation.", + "example": "a1c4e7b2-8f3d-4a6e-9c2b-5d8f1e4a7b3c" + }, + "config": { + "type": "object", + "properties": { + "revisionId": { + "type": "string", + "deprecated": true, + "description": "Deprecated: This field will be automatically set to the latest revision ID." + }, + "createdBy": { + "type": "string", + "description": "The person who created the config, in the format of \"consumer:{consumer-id}\" or \"builder:{builder-id}\"." + }, + "content": { + "$ref": "#/components/schemas/UpdateInstallationConfigContent", + "description": "The content of the config." + } + }, + "description": "The config of the installation." + } + }, + "description": "The installation fields to update. Only fields whose paths are listed in `updateMask` will be\napplied; all other fields in this object are ignored.\n" + } + } + }, + "example": { + "updateMask": [ + "config.content.read.objects.contacts" + ], + "installation": { + "config": { + "content": { + "read": { + "objects": { + "contacts": { + "objectName": "contacts", + "schedule": "*/30 * * * *", + "destination": "contactsWebhook", + "selectedFields": { + "email": true, + "phone": true + } + } + } + } + } + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The updated installation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + } + }, + "400": { + "description": "Invalid input (e.g. unrecognized update mask path, missing value for a mask, or malformed request body).", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity. Returned when the config is invalid, or when the sample read fails because a selected field or mapping is not visible to the connected user.", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "installationUpdate" + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/objects/{objectName}/config-content": { + "patch": { + "summary": "Update an installation object", + "description": "Updates a single object's configuration within an installation using JSON Patch syntax.\n", + "operationId": "patchObjectConfigContent", + "tags": [ + "Installation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The integration ID.", + "schema": { + "type": "string" + } + }, + { + "name": "objectName", + "in": "path", + "required": true, + "description": "The object name whose config content will be patched.\nMust match an object name defined in the integration's manifest for the specified action type (read, subscribe, or write).\nCommon examples include: `account`, `contact`, `lead`, `opportunity` (for Salesforce), `deal`, `company` (for HubSpot), etc.\n", + "schema": { + "type": "string" + }, + "example": "account" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "oneOf": [ + { + "type": "object", + "required": [ + "groupRef", + "action", + "changes" + ], + "properties": { + "groupRef": { + "type": "string", + "description": "The ID of the user group that has access to this installation.\nEither groupRef or installationId must be provided.\n", + "example": "group-123" + }, + "action": { + "type": "string", + "enum": [ + "read", + "subscribe", + "write" + ], + "description": "The action type for the object config (read, subscribe, or write).", + "example": "read" + }, + "changes": { + "type": "array", + "minItems": 1, + "description": "Array of JSON Patch operations to apply.\n", + "items": { + "$ref": "#/components/schemas/JSONPatchOperation" + }, + "example": [ + { + "op": "replace", + "path": "/schedule", + "value": "*/10 * * * *" + }, + { + "op": "add", + "path": "/selectedFields/phone", + "value": true + }, + { + "op": "remove", + "path": "/selectedFields/billingcity" + } + ] + } + } + }, + { + "type": "object", + "required": [ + "installationId", + "action", + "changes" + ], + "properties": { + "installationId": { + "type": "string", + "description": "The installation ID.\nEither groupRef or installationId must be provided.\n", + "example": "installation-123" + }, + "action": { + "type": "string", + "enum": [ + "read", + "subscribe", + "write" + ], + "description": "The action type for the object config (read, subscribe, or write).", + "example": "read" + }, + "changes": { + "type": "array", + "minItems": 1, + "description": "Array of JSON Patch operations to apply.\n", + "items": { + "$ref": "#/components/schemas/JSONPatchOperation" + }, + "example": [ + { + "op": "replace", + "path": "/schedule", + "value": "*/10 * * * *" + }, + { + "op": "add", + "path": "/selectedFields/phone", + "value": true + }, + { + "op": "remove", + "path": "/selectedFields/billingcity" + } + ] + } + } + } + ] + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The updated installation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "404": { + "description": "Installation not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "patchObjectConfigContent" + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/objects/{objectName}/metadata": { + "get": { + "summary": "Get object metadata via installation", + "description": "Retrieves metadata about an object in a customer's SaaS instance, including its fields. An installation must exist for the given `groupRef` and `integrationId`. The `objectName` can be either the mapped name from your integration config or the native provider name. For Salesforce, nested fields may be included using JSONPath bracket notation (e.g. `$['billingaddress']['city']`).\n", + "tags": [ + "Objects & Fields" + ], + "operationId": "getObjectMetadataForInstallation", + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The unique identifier of the integration.", + "schema": { + "type": "string" + }, + "example": "e3a7f9c1-4b2d-4e8a-9f6b-2d5c8a1e3b7f" + }, + { + "name": "objectName", + "in": "path", + "required": true, + "description": "The name of the object to retrieve metadata for. You can use either the mapped name from your integration config (e.g. `people`) or the native provider object name (e.g. `contact`).\n", + "schema": { + "type": "string" + }, + "example": "account" + }, + { + "name": "groupRef", + "in": "query", + "required": true, + "description": "The ID of the user group that has access to this installation.", + "example": "group-123", + "schema": { + "type": "string" + } + }, + { + "name": "excludeReadOnly", + "in": "query", + "required": false, + "description": "Excludes fields where `ReadOnly` is `true` from the response.", + "example": true, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The retrieved object metadata.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjectMetadata" + }, + "example": { + "name": "account", + "displayName": "Account", + "mappedObjectName": "companies", + "fields": { + "name": { + "fieldName": "name", + "displayName": "Account Name", + "valueType": "string", + "providerType": "string", + "readOnly": false, + "isCustom": false, + "isRequired": true + }, + "billingcity": { + "fieldName": "billingcity", + "displayName": "Billing City", + "valueType": "string", + "providerType": "string", + "readOnly": false, + "isCustom": false, + "isRequired": false + }, + "industry": { + "fieldName": "industry", + "displayName": "Industry", + "valueType": "singleSelect", + "providerType": "picklist", + "readOnly": false, + "isCustom": false, + "isRequired": false, + "values": [ + { + "value": "technology", + "displayValue": "Technology" + }, + { + "value": "finance", + "displayValue": "Finance" + } + ] + } + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/installations": { + "get": { + "summary": "List installations for a project", + "description": "Lists all installations across every integration in a project, giving you a complete view of all active customer integrations. To narrow results to a single integration, use listInstallations instead.\n", + "operationId": "listInstallationsForProject", + "tags": [ + "Installation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "groupRef", + "in": "query", + "description": "The ID that your app uses to identify a group of users (e.g. an org ID, workspace ID, or team ID). When provided, only returns installations belonging to this group.", + "example": "group-123", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of installations", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Installation" + } + }, + "example": [ + { + "id": "3f8b2a1e-7c4d-4e9a-b5f6-1d2e3a4b5c6d", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "integrationId": "550e8400-e29b-41d4-a716-446655440000", + "group": { + "groupRef": "org_12345", + "groupName": "Acme Corp", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "healthStatus": "healthy", + "connection": { + "id": "9d8c7b6a-5e4f-3a2b-1c0d-ef9876543210", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "provider": "salesforce", + "group": { + "groupRef": "org_12345", + "groupName": "Acme Corp", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "consumer": { + "consumerRef": "user_67890", + "consumerName": "Jane Smith", + "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "createTime": "2024-01-15T10:30:00.000000Z" + }, + "createTime": "2024-01-15T10:30:00.000000Z", + "authScheme": "oauth2/authorizationCode", + "status": "working" + }, + "createTime": "2024-01-15T10:30:00.000000Z", + "createdBy": "consumer:user_67890", + "config": { + "id": "e4d3c2b1-a098-7654-3210-fedcba987654", + "revisionId": "f0e1d2c3-b4a5-6789-0abc-def123456789", + "createTime": "2024-01-15T10:30:00.000000Z", + "createdBy": "consumer:user_67890", + "content": { + "provider": "salesforce", + "read": { + "objects": { + "account": { + "objectName": "account", + "schedule": "*/15 * * * *", + "destination": "accountWebhook", + "selectedFields": { + "name": true, + "industry": true + } + } + } + } + } + } + } + ] + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/providers/{provider}/objects/{objectName}/metadata": { + "get": { + "summary": "Get object metadata via connection", + "description": "Retrieves metadata about an object in a customer's SaaS instance, including its fields. A connection must exist for the given `groupRef` and `provider`. For Salesforce, nested fields may be included using JSONPath bracket notation (e.g. `$['billingaddress']['city']`).\n", + "tags": [ + "Objects & Fields" + ], + "operationId": "getObjectMetadataForConnection", + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "provider", + "in": "path", + "required": true, + "description": "The provider name (e.g. `salesforce`, `hubspot`).", + "schema": { + "type": "string" + }, + "example": "salesforce" + }, + { + "name": "objectName", + "in": "path", + "required": true, + "description": "The native provider object name to retrieve metadata for.", + "schema": { + "type": "string" + }, + "example": "contact" + }, + { + "name": "groupRef", + "in": "query", + "required": true, + "description": "The ID of the user group whose connection should be used to fetch the metadata.", + "example": "group-123", + "schema": { + "type": "string" + } + }, + { + "name": "excludeReadOnly", + "in": "query", + "required": false, + "description": "Excludes fields where `ReadOnly` is `true` from the response.", + "example": true, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The retrieved object metadata.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjectMetadata" + }, + "example": { + "name": "contact", + "displayName": "Contact", + "fields": { + "firstname": { + "fieldName": "firstname", + "displayName": "First Name", + "valueType": "string", + "providerType": "string", + "readOnly": false, + "isCustom": false, + "isRequired": true + }, + "email": { + "fieldName": "email", + "displayName": "Email", + "valueType": "string", + "providerType": "string", + "readOnly": false, + "isCustom": false, + "isRequired": false + }, + "lifecyclestage": { + "fieldName": "lifecyclestage", + "displayName": "Lifecycle Stage", + "valueType": "singleSelect", + "providerType": "enumeration", + "readOnly": false, + "isCustom": false, + "isRequired": false, + "values": [ + { + "value": "lead", + "displayValue": "Lead" + }, + { + "value": "customer", + "displayValue": "Customer" + } + ] + } + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/object-metadata": { + "put": { + "summary": "Upsert custom fields for installation", + "operationId": "upsertMetadataForInstallation", + "description": "Create or update fields in the SaaS instance tied to an installation. Only HubSpot and Salesforce are supported currently.", + "tags": [ + "Objects & Fields" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The integration ID.", + "schema": { + "type": "string" + }, + "example": "32356abe-d2fd-49c7-9030-abdcbc6456d4" + } + ], + "requestBody": { + "required": true, + "description": "Metadata upsert request containing field definitions to create or update", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertMetadataRequest" + }, + "examples": { + "createTextFields": { + "summary": "Create text fields on multiple objects", + "value": { + "groupRef": "group-123", + "fields": { + "Account": [ + { + "fieldName": "Industry", + "displayName": "Industry Sector", + "description": "The industry this account operates in", + "valueType": "string", + "required": false, + "stringOptions": { + "length": 255, + "defaultValue": "Technology" + } + }, + { + "fieldName": "Company_Size", + "displayName": "Company Size", + "valueType": "string", + "stringOptions": { + "values": [ + "Small", + "Medium", + "Large", + "Enterprise" + ], + "valuesRestricted": true + } + } + ], + "Contact": [ + { + "fieldName": "Seniority_Level", + "displayName": "Seniority Level", + "valueType": "string", + "stringOptions": { + "values": [ + "Junior", + "Mid", + "Senior", + "Executive" + ], + "valuesRestricted": true + } + } + ] + } + } + }, + "createNumericFields": { + "summary": "Create numeric fields with constraints", + "value": { + "groupRef": "group-123", + "fields": { + "Opportunity": [ + { + "fieldName": "Deal_Score", + "displayName": "Deal Score", + "description": "Likelihood score from 0-100", + "valueType": "float", + "required": true, + "numericOptions": { + "precision": 5, + "scale": 2, + "min": 0, + "max": 100, + "defaultValue": 50 + } + } + ] + } + } + }, + "createAssociationField": { + "summary": "Create field with association to another object", + "value": { + "groupRef": "group-123", + "fields": { + "Task": [ + { + "fieldName": "Related_Contact", + "displayName": "Related Contact", + "valueType": "string", + "association": { + "associationType": "lookup", + "targetObject": "Contact", + "targetField": "Id", + "cardinality": "many-to-one", + "required": false, + "labels": { + "singular": "Contact", + "plural": "Contacts" + } + } + } + ] + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Metadata creation completed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertMetadataResponse" + } + } + } + }, + "400": { + "description": "Invalid request payload or validation errors", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "403": { + "description": "Insufficient permissions for metadata operations", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "404": { + "description": "Project, integration, or installation not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/providers/{provider}/object-metadata": { + "put": { + "summary": "Upsert custom fields for connection", + "operationId": "upsertMetadataForConnection", + "description": "Create or update fields in the SaaS instance tied to a connection. Only HubSpot and Salesforce are supported currently.", + "tags": [ + "Objects & Fields" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "provider", + "in": "path", + "required": true, + "description": "The provider that this connection connects to.", + "schema": { + "type": "string" + }, + "example": "salesforce" + } + ], + "requestBody": { + "required": true, + "description": "Metadata upsert request containing field definitions to create or update", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertMetadataRequest" + }, + "examples": { + "createTextFields": { + "summary": "Create text fields on multiple objects", + "value": { + "groupRef": "group-123", + "fields": { + "Account": [ + { + "fieldName": "Industry", + "displayName": "Industry Sector", + "description": "The industry this account operates in", + "valueType": "string", + "required": false, + "stringOptions": { + "length": 255, + "defaultValue": "Technology" + } + }, + { + "fieldName": "Company_Size", + "displayName": "Company Size", + "valueType": "string", + "stringOptions": { + "values": [ + "Small", + "Medium", + "Large", + "Enterprise" + ], + "valuesRestricted": true + } + } + ], + "Contact": [ + { + "fieldName": "Seniority_Level", + "displayName": "Seniority Level", + "valueType": "string", + "stringOptions": { + "values": [ + "Junior", + "Mid", + "Senior", + "Executive" + ], + "valuesRestricted": true + } + } + ] + } + } + }, + "createNumericFields": { + "summary": "Create numeric fields with constraints", + "value": { + "groupRef": "group-123", + "fields": { + "Opportunity": [ + { + "fieldName": "Deal_Score", + "displayName": "Deal Score", + "description": "Likelihood score from 0-100", + "valueType": "float", + "required": true, + "numericOptions": { + "precision": 5, + "scale": 2, + "min": 0, + "max": 100, + "defaultValue": 50 + } + } + ] + } + } + }, + "createAssociationField": { + "summary": "Create field with association to another object", + "value": { + "groupRef": "group-123", + "fields": { + "Task": [ + { + "fieldName": "Related_Contact", + "displayName": "Related Contact", + "valueType": "string", + "association": { + "associationType": "lookup", + "targetObject": "Contact", + "targetField": "Id", + "cardinality": "many-to-one", + "required": false, + "labels": { + "singular": "Contact", + "plural": "Contacts" + } + } + } + ] + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Metadata creation completed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertMetadataResponse" + } + } + } + }, + "400": { + "description": "Invalid request payload or validation errors", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "403": { + "description": "Insufficient permissions for metadata operations", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "404": { + "description": "Project or connection not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/installations/{installationId}/operations": { + "get": { + "summary": "List operations", + "operationId": "listOperations", + "tags": [ + "Operation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The integration ID.", + "schema": { + "type": "string" + } + }, + { + "name": "installationId", + "in": "path", + "required": true, + "description": "The Ampersand installation ID.", + "schema": { + "type": "string" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1000, + "default": 200 + }, + "description": "The number of operations to return." + }, + { + "name": "pageToken", + "in": "query", + "schema": { + "type": "string" + }, + "description": "A cursor that can be passed to paginate through multiple pages of operations." + } + ], + "responses": { + "200": { + "description": "List of operations", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "results", + "pagination" + ], + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Operation" + } + }, + "pagination": { + "$ref": "#/components/schemas/PaginationInfo" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/integrations/{integrationId}/installations/{installationId}/objects/{objectName}/backfill-progress": { + "get": { + "summary": "Get backfill progress", + "operationId": "getBackfillProgress", + "tags": [ + "Operation" + ], + "description": "Retrieve backfill progress (records processed, estimated total) for an object. Use to track progress of an initial data sync.", + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "integrationId", + "in": "path", + "required": true, + "description": "The Ampersand integration ID.", + "schema": { + "type": "string" + }, + "example": "113e9685-9a51-42cc-8662-9d9725b17f14" + }, + { + "name": "installationId", + "in": "path", + "required": true, + "description": "The Ampersand installation ID.", + "schema": { + "type": "string" + }, + "example": "66438162-5299-4669-a41d-85c5a3b1a83e" + }, + { + "name": "objectName", + "in": "path", + "required": true, + "description": "Name of the object being synced (e.g., \"contact\", \"account\").", + "schema": { + "type": "string" + }, + "example": "contact" + } + ], + "responses": { + "200": { + "description": "Backfill progress for the object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackfillProgress" + }, + "example": { + "installationId": "66438162-5299-4669-a41d-85c5a3b1a83e", + "objectName": "contact", + "operationId": "3efc0f0f-4bb9-498f-996c-9893d98ca4b5", + "recordsProcessed": 1250, + "recordsEstimatedTotal": 5000, + "createTime": "2025-02-13T10:00:00Z", + "updateTime": "2025-02-13T10:05:00Z" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "404": { + "description": "No backfill operation found or progress not available", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/operations/{operationId}": { + "get": { + "summary": "Get an operation", + "description": "Retrieve a single operation by ID. An operation represents an async read, write, or subscribe action for an installation. Use this endpoint to poll for status, inspect the result summary, or fetch metadata such as read progress or write outcome details.\n", + "operationId": "getOperation", + "tags": [ + "Operation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "operationId", + "in": "path", + "required": true, + "description": "Unique identifier for the operation. Obtain from the list operations API endpoint, the Ampersand dashboard, or webhook payloads.", + "schema": { + "type": "string" + }, + "example": "3efc0f0f-4bb9-498f-996c-9893d98ca4b5" + } + ], + "responses": { + "200": { + "description": "The operation, including its current status, result summary, and metadata (e.g. read progress or write results).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + }, + "examples": { + "readSuccess": { + "summary": "Completed read (no new data)", + "value": { + "projectId": "123e4567-e89b-12d3-a456-426614174000", + "integrationId": "113e9685-9a51-42cc-8662-9d9725b17f14", + "installationId": "66438162-5299-4669-a41d-85c5a3b1a83e", + "configId": "a1b2c3d4-e5f6-4789-a012-3456789abcde", + "actionType": "read", + "status": "success", + "id": "3efc0f0f-4bb9-498f-996c-9893d98ca4b5", + "result": "[contact] No new data found", + "metadata": { + "objects": [ + "contact" + ] + }, + "createTime": "2023-07-13T21:34:44.816354Z" + } + }, + "readProgress": { + "summary": "Read with progress", + "value": { + "projectId": "123e4567-e89b-12d3-a456-426614174000", + "integrationId": "113e9685-9a51-42cc-8662-9d9725b17f14", + "installationId": "66438162-5299-4669-a41d-85c5a3b1a83e", + "configId": "a1b2c3d4-e5f6-4789-a012-3456789abcde", + "actionType": "read", + "status": "in_progress", + "id": "3efc0f0f-4bb9-498f-996c-9893d98ca4b5", + "metadata": { + "objects": [ + "contact" + ], + "progress": { + "installationId": "66438162-5299-4669-a41d-85c5a3b1a83e", + "objectName": "contact", + "operationId": "3efc0f0f-4bb9-498f-996c-9893d98ca4b5", + "recordsProcessed": 1250, + "recordsEstimatedTotal": 5000 + } + }, + "createTime": "2023-07-13T21:34:44.816354Z" + } + }, + "writeSuccess": { + "summary": "Completed write with successful record IDs", + "value": { + "projectId": "123e4567-e89b-12d3-a456-426614174000", + "integrationId": "113e9685-9a51-42cc-8662-9d9725b17f14", + "installationId": "66438162-5299-4669-a41d-85c5a3b1a83e", + "configId": "a1b2c3d4-e5f6-4789-a012-3456789abcde", + "actionType": "write", + "status": "success", + "id": "7a8b9c0d-1e2f-4a5b-8c9d-0e1f2a3b4c5d", + "result": "Batch write completed (2 succeeded, 0 failed)", + "metadata": { + "objects": [ + "contact" + ], + "successfulRecordIds": [ + "001xx000003DGbYAAW", + "001xx000003DGbZAAW" + ] + }, + "createTime": "2023-07-13T22:10:00.000000Z" + } + } + } + } + } + }, + "default": { + "description": "Error response for any non-2xx status (e.g. operation not found, invalid project or operation ID, or server error).\n", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + }, + "example": { + "type": "https://httpstatuses.com/404", + "title": "Not Found", + "status": 404, + "detail": "Operation not found for the given operation ID.", + "subsystem": "api", + "time": "2024-04-22T18:55:28.456076Z", + "requestId": "89eb1ffb-2a54-4105-aaae-7bf990f1aa69#87715", + "remedy": "Verify the operation ID and project are correct, or list operations to find a valid ID.", + "retryable": false + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/operations/{operationId}/logs": { + "get": { + "summary": "List logs for an operation", + "operationId": "listOperationLogs", + "tags": [ + "Operation" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "operationId", + "in": "path", + "required": true, + "description": "Operation ID.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of logs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Log" + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/providers": { + "get": { + "summary": "List providers", + "description": "Returns all supported SaaS providers and their capabilities. The response is a JSON object keyed by provider name (e.g. `salesforce`, `hubspot`). Each value describes the provider's authentication type, supported operations, modules, and configuration options. No authentication is required.\n", + "operationId": "listProviders", + "tags": [ + "Provider" + ], + "security": [], + "responses": { + "200": { + "description": "All available providers and their capabilities.\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogType" + }, + "example": { + "salesforce": { + "name": "salesforce", + "displayName": "Salesforce", + "authType": "oauth2", + "baseURL": "https://{{.workspace}}.my.salesforce.com", + "defaultModule": "crm", + "support": { + "read": true, + "write": true, + "delete": true, + "subscribe": true, + "proxy": true, + "bulkWrite": { + "insert": true, + "update": true, + "upsert": true, + "delete": true + }, + "search": { + "operators": { + "equals": true + } + } + }, + "providerOpts": {} + }, + "hubspot": { + "name": "hubspot", + "displayName": "HubSpot", + "authType": "oauth2", + "baseURL": "https://api.hubapi.com", + "defaultModule": "", + "support": { + "read": true, + "write": true, + "delete": true, + "subscribe": true, + "proxy": true, + "bulkWrite": { + "insert": false, + "update": false, + "upsert": false, + "delete": false + }, + "search": { + "operators": { + "equals": true + } + } + }, + "providerOpts": {} + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/providers/{provider}": { + "get": { + "summary": "Get provider", + "description": "Returns information about a single provider. No authentication is required.\n", + "operationId": "getProvider", + "tags": [ + "Provider" + ], + "security": [], + "parameters": [ + { + "name": "provider", + "in": "path", + "required": true, + "description": "The provider name (e.g. `salesforce`, `hubspot`).", + "example": "hubspot", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The requested provider.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderInfo" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/api-keys": { + "get": { + "x-speakeasy-ignore": true, + "summary": "List API keys", + "operationId": "listApiKeys", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "active", + "in": "query", + "description": "Whether to include only active API keys. If false, all API keys are included.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of API keys", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "post": { + "x-speakeasy-ignore": true, + "summary": "Create a new API key", + "operationId": "createApiKey", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + }, + "404": { + "description": "Project not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "apiKey" + } + }, + "/projects/{projectIdOrName}/api-keys/{apiKey}": { + "get": { + "x-speakeasy-ignore": true, + "summary": "Get an API key", + "operationId": "getApiKey", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "apiKey", + "in": "path", + "required": true, + "description": "API key to access Ampersand APIs.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + }, + "404": { + "description": "API key not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "delete": { + "x-speakeasy-ignore": true, + "summary": "Delete an API key", + "operationId": "deleteApiKey", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "apiKey", + "in": "path", + "required": true, + "description": "API key to access Ampersand APIs.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "404": { + "description": "Not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + } + } + }, + "patch": { + "x-speakeasy-ignore": true, + "summary": "Update an API key", + "operationId": "updateApiKey", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "apiKey", + "in": "path", + "required": true, + "description": "API key to access Ampersand APIs.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PatchApiKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "API key updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/connections": { + "get": { + "summary": "List connections", + "operationId": "listConnections", + "tags": [ + "Connection" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "provider", + "in": "query", + "description": "The provider name (e.g. \"salesforce\", \"hubspot\")", + "schema": { + "type": "string" + } + }, + { + "name": "groupRef", + "in": "query", + "description": "The ID of the user group that has access to this installation.", + "example": "group-123", + "schema": { + "type": "string" + } + }, + { + "name": "consumerRef", + "in": "query", + "description": "The consumer reference.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of project connections.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Connection" + } + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/connections:generate": { + "post": { + "summary": "Generate a new connection", + "description": "All auth schemes are supported, but for OAuth2 Authorization Code, it is recommended that you use the [/oauth-connect endpoint](https://docs.withampersand.com/reference/oauth/get-url-for-oauth-flow) instead, unless you already have the refresh token and are importing it into Ampersand.", + "operationId": "generateConnection", + "tags": [ + "Connection" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateConnectionRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Connection" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "generateConnectionParams" + } + }, + "/projects/{projectIdOrName}/connections/{connectionId}": { + "get": { + "summary": "Get a connection", + "operationId": "getConnection", + "tags": [ + "Connection" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "connectionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "includeCreds", + "in": "query", + "schema": { + "type": "boolean" + }, + "description": "Whether to include credentials for `oauth2AuthorizationCode` in the response. If true, `accessToken` and `scopes` are included. To include `refreshToken` as well, set `includeRefreshToken` to true. Default is false." + }, + { + "name": "includeRefreshToken", + "in": "query", + "schema": { + "type": "boolean" + }, + "description": "Whether to include `refreshToken` for `oauth2AuthorizationCode` credentials in the response (along with `accessToken` and `scopes`). If true, the `includeCreds` query parameter will be ignored. Default is false." + }, + { + "name": "refresh", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "force", + "ifExpired" + ] + }, + "description": "Whether to refresh the access token. If value is `ifExpired`, the access token will be refreshed only if it has expired. If value is `force`, the access token will be refreshed regardless of its expiration." + } + ], + "responses": { + "200": { + "description": "Connection", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Connection" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "patch": { + "summary": "Update a connection.", + "description": "Rotate credentials or update metadata (such as the provider workspace reference) for an existing connection.", + "operationId": "updateConnection", + "tags": [ + "Connection" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The Ampersand project ID or project name.", + "example": "my-project" + }, + { + "name": "connectionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The ID of the connection to update. You can find this via the [list connections endpoint](https://docs.withampersand.com/reference/connection/list-connections).", + "example": "connection-123" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateConnectionRequest" + }, + "examples": { + "rotateApiKey": { + "summary": "Rotate an API key", + "value": { + "updateMask": [ + "apiKey" + ], + "connection": { + "apiKey": "new-api-key-value" + } + } + }, + "updateBasicAuth": { + "summary": "Update basic auth credentials", + "value": { + "updateMask": [ + "basicAuth" + ], + "connection": { + "basicAuth": { + "username": "new-username", + "password": "new-password" + } + } + } + }, + "updateWorkspaceRef": { + "summary": "Update provider workspace reference", + "value": { + "updateMask": [ + "providerWorkspaceRef" + ], + "connection": { + "providerWorkspaceRef": "new-workspace-id" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Connection updated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Connection" + }, + "example": { + "id": "c3a1f9d2-7b4e-4f8a-9e6d-2c5b8a3f1e7d", + "projectId": "a1b2c3d4-e5f6-4789-a012-3456789abcde", + "provider": "salesforce", + "group": { + "groupRef": "8f2e4a6b-1c3d-4e5f-9a7b-0d8e6f2c4a1b", + "groupName": "my-group" + }, + "consumer": { + "consumerRef": "d4e5f6a7-b8c9-4d0e-a1f2-3b4c5d6e7f8a", + "consumerName": "my-consumer" + }, + "providerWorkspaceRef": "my-org.my.salesforce.com", + "authScheme": "apiKey", + "status": "working", + "createTime": "2023-07-13T21:34:44.816354Z", + "updateTime": "2024-01-15T10:22:33.000000Z" + } + } + } + }, + "400": { + "description": "Invalid update mask or request body. The response includes the list of allowed mask values.", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + }, + "example": { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "Invalid update mask", + "subsystem": "api", + "time": "2024-04-22T18:55:28.456076Z", + "requestId": "89eb1ffb-2a54-4105-aaae-7bf990f1aa69#87715", + "remedy": "Allowed masks: 'providerWorkspaceRef, providerMetadata, apiKey, basicAuth, oauth2ClientCredentials, oauth2PasswordCredentials'", + "retryable": false + } + } + } + }, + "default": { + "description": "Error (e.g. connection not found, auth scheme mismatch, or server error).", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "delete": { + "summary": "Delete a connection", + "operationId": "deleteConnection", + "tags": [ + "Connection" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "connectionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/destinations": { + "post": { + "summary": "Create a new destination", + "operationId": "createDestination", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "name", + "type", + "metadata" + ], + "properties": { + "name": { + "type": "string", + "description": "Name for the new destination. Must be unique within the project and can only contain letters, numbers and dashes.", + "example": "leadConvertedWebhook" + }, + "type": { + "type": "string", + "description": "The type of the destination.", + "example": "webhook", + "enum": [ + "webhook", + "kinesis", + "s3" + ] + }, + "secrets": { + "type": "object", + "description": "Secrets for the destination.", + "properties": { + "awsKeyId": { + "type": "string", + "description": "The AWS access key ID for the Kinesis or S3 destination.", + "example": "AKIAIOSFODNN7EXAMPLE", + "x-go-type-skip-optional-pointer": true + }, + "awsSecretKey": { + "type": "string", + "description": "The AWS secret access key for the Kinesis or S3 destination.", + "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "x-go-type-skip-optional-pointer": true + }, + "awsSessionToken": { + "type": "string", + "description": "The AWS session token for the Kinesis or S3 destination.", + "example": "AQoEXAMPLEH4aoAH0gNCAPy...", + "x-go-type-skip-optional-pointer": true + } + } + }, + "metadata": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Webhook URL, must start with \"https://\".", + "example": "https://webhooks.mailmonkey.com/salesforce-lead-converted" + }, + "headers": { + "$ref": "#/components/schemas/WebhookHeaders" + }, + "region": { + "type": "string", + "description": "The AWS region where the Kinesis or S3 destination is hosted.", + "example": "us-east-1", + "x-go-type-skip-optional-pointer": true + }, + "streamName": { + "type": "string", + "description": "The name of the Kinesis stream to send events to.", + "example": "my-kinesis-stream", + "x-go-type-skip-optional-pointer": true + }, + "endpointUrl": { + "type": "string", + "description": "The endpoint URL for the Kinesis stream.", + "example": "https://kinesis.us-east-1.amazonaws.com", + "x-go-type-skip-optional-pointer": true + }, + "partitionKeyTemplate": { + "type": "string", + "description": "The template for the partition key to use when sending events to Kinesis (a JMESPath template)", + "example": "data.user_id", + "x-go-type-skip-optional-pointer": true + }, + "bucket": { + "type": "string", + "description": "The name of the S3 bucket to write objects to.", + "example": "ampersand-integration-bucket", + "x-go-type-skip-optional-pointer": true + }, + "keyTemplate": { + "type": "string", + "description": "The template for the S3 object key to use when writing objects (a JMESPath template). If omitted, the key defaults to the message timestamp followed by the message ID.", + "example": "join('/', [metadata.objectName, metadata.operationId])", + "x-go-type-skip-optional-pointer": true + }, + "storageClass": { + "type": "string", + "description": "The S3 storage class for written objects. Defaults to STANDARD. Common values include STANDARD, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, GLACIER, GLACIER_IR, and DEEP_ARCHIVE.", + "example": "STANDARD", + "x-go-type-skip-optional-pointer": true + } + } + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Destination" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "destination" + }, + "get": { + "summary": "List destinations", + "operationId": "listDestinations", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "responses": { + "200": { + "description": "List of destinations", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Destination" + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/destinations/{destination}": { + "get": { + "summary": "Get a destination", + "operationId": "getDestination", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The destination name.", + "example": "leadConvertedWebhook" + }, + { + "name": "includeSecrets", + "in": "query", + "required": false, + "description": "Include secrets in the response", + "schema": { + "type": "boolean" + }, + "example": true + }, + { + "name": "rotate", + "in": "query", + "required": false, + "description": "Rotate the destination secrets", + "schema": { + "type": "boolean" + }, + "example": true + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DestinationWithSecrets" + } + } + } + }, + "404": { + "description": "Destination not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "patch": { + "summary": "Update a destination", + "operationId": "updateDestination", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The destination ID." + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "updateMask", + "destination" + ], + "properties": { + "updateMask": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field paths specifying which fields to update. Allowed values include:\n- name\n- metadata.url\n- metadata.headers\n- metadata.region\n- metadata.streamName\n- metadata.endpointUrl\n- metadata.partitionKeyTemplate\n- metadata.bucket\n- metadata.keyTemplate\n- metadata.storageClass\n- secrets.awsKeyId\n- secrets.awsSecretKey\n- secrets.awsSessionToken\n", + "example": [ + "name", + "metadata.url", + "metadata.region", + "metadata.streamName" + ] + }, + "destination": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "User-friendly name for the destination", + "example": "leadConvertedWebhook" + }, + "metadata": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Webhook URL", + "example": "https://webhooks.mailmonkey.com/salesforce-lead-converted" + }, + "headers": { + "$ref": "#/components/schemas/WebhookHeaders" + }, + "region": { + "type": "string", + "description": "The AWS region where the Kinesis or S3 destination is hosted.", + "example": "us-east-1" + }, + "streamName": { + "type": "string", + "description": "The name of the Kinesis stream to send events to.", + "example": "my-kinesis-stream" + }, + "endpointUrl": { + "type": "string", + "description": "The endpoint URL for the Kinesis stream.", + "example": "https://kinesis.us-east-1.amazonaws.com" + }, + "partitionKeyTemplate": { + "type": "string", + "description": "The template for the partition key to use when sending events to Kinesis (a JMESPath template)", + "example": "data.user_id" + }, + "bucket": { + "type": "string", + "description": "The name of the S3 bucket to write objects to.", + "example": "ampersand-integration-bucket" + }, + "keyTemplate": { + "type": "string", + "description": "The template for the S3 object key to use when writing objects (a JMESPath template). If omitted, the key defaults to the message timestamp followed by the message ID.", + "example": "join('/', [metadata.objectName, metadata.operationId])" + }, + "storageClass": { + "type": "string", + "description": "The S3 storage class for written objects. Defaults to STANDARD. Common values include STANDARD, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, GLACIER, GLACIER_IR, and DEEP_ARCHIVE.", + "example": "STANDARD" + } + } + }, + "secrets": { + "type": "object", + "description": "Secrets for the destination.", + "properties": { + "awsKeyId": { + "type": "string", + "description": "The AWS access key ID for the Kinesis or S3 destination.", + "example": "AKIAIOSFODNN7EXAMPLE" + }, + "awsSecretKey": { + "type": "string", + "description": "The AWS secret access key for the Kinesis or S3 destination.", + "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + }, + "awsSessionToken": { + "type": "string", + "description": "The AWS session token for the Kinesis or S3 destination.", + "example": "AQoEXAMPLEH4aoAH0gNCAPy..." + } + } + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Destination" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "404": { + "description": "Destination not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "destinationUpdate" + }, + "delete": { + "summary": "Delete a destination", + "operationId": "deleteDestination", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The destination ID" + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/generate-upload-url": { + "get": { + "summary": "Generate a signed URL to upload a zip file to.", + "operationId": "generateUploadUrl", + "tags": [ + "Upload URL" + ], + "responses": { + "200": { + "description": "Signed URL", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SignedUrl" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/orgs": { + "post": { + "x-speakeasy-ignore": true, + "summary": "Create a new organization", + "operationId": "createOrg", + "tags": [ + "Org" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "label" + ], + "type": "object", + "properties": { + "label": { + "type": "string", + "description": "The organization label.", + "example": "org-123" + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The newly created org", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Org" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "org" + } + }, + "/orgs/{orgId}": { + "get": { + "x-speakeasy-ignore": true, + "summary": "Get an organization", + "operationId": "getOrg", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + ], + "responses": { + "200": { + "description": "Organization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Org" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "patch": { + "x-speakeasy-ignore": true, + "summary": "Update an organization", + "operationId": "updateOrg", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "updateMask", + "org" + ], + "properties": { + "updateMask": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field paths specifying which fields to update. Allowed values include:\n- label\n", + "example": [ + "label" + ] + }, + "org": { + "type": "object", + "properties": { + "label": { + "type": "string", + "description": "The organization label.", + "example": "org-123" + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Updated org", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Org" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "orgUpdate" + } + }, + "/orgs/{orgId}/builders": { + "get": { + "summary": "List builders for an organization", + "operationId": "listOrgBuilders", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + ], + "responses": { + "200": { + "description": "List of builders that are a part of the org", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Builder" + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/orgs/{orgId}/invites": { + "post": { + "x-speakeasy-ignore": true, + "summary": "Invite a user to an organization", + "operationId": "createOrgInvite", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "email" + ], + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "The email address of the user to invite.", + "example": "alice@company.com" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "The newly created invite", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Invite" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "invite" + }, + "get": { + "x-speakeasy-ignore": true, + "summary": "List invites for an organization", + "operationId": "listOrgInvites", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + ], + "responses": { + "200": { + "description": "List of invites", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Invite" + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/orgs/{orgId}/invites/{inviteId}": { + "get": { + "x-speakeasy-ignore": true, + "summary": "Get an invite", + "operationId": "getOrgInvite", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + }, + { + "name": "inviteId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Invite", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Invite" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "delete": { + "x-speakeasy-ignore": true, + "summary": "Revoke an invite", + "operationId": "deleteOrgInvite", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + }, + { + "name": "inviteId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/orgs/{orgId}/memberships": { + "post": { + "summary": "Add user to an organization", + "description": "Adds a builder to an organization. Two authorization modes - Org owner inviting another user, or self-joining via claimed domain (authenticated user's email domain should be claimed by this organization).", + "operationId": "addUserToOrg", + "tags": [ + "Org" + ], + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "builderId" + ], + "properties": { + "builderId": { + "type": "string", + "description": "The ID of the builder to add to the organization", + "example": "builder-id-123" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "User successfully added to organization" + }, + "400": { + "description": "Bad Request - Membership already exists or invalid request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "403": { + "description": "Forbidden - Requires org:owner permission", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "404": { + "description": "Not Found - Organization or builder not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/my-info": { + "get": { + "x-speakeasy-ignore": true, + "summary": "Get information about the current user", + "operationId": "getMyInfo", + "tags": [ + "User" + ], + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "Information about the current user and their organizations and projects", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BuilderInfo" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/invites:accept": { + "post": { + "x-speakeasy-ignore": true, + "summary": "Accept an invite", + "operationId": "acceptInvite", + "tags": [ + "User" + ], + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "invitedEmail" + ], + "properties": { + "invitedEmail": { + "type": "string", + "description": "The email address that the invite was sent to" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Information about the current user and their organizations and projects", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BuilderInfo" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/orgs/{orgId}/billingAccount": { + "get": { + "x-speakeasy-ignore": true, + "summary": "Get the billing account for an organization", + "operationId": "getOrgBillingAccount", + "tags": [ + "Billing Account" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "description": "ID of the organization.", + "schema": { + "type": "string" + }, + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + } + ], + "responses": { + "200": { + "description": "Billing account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BillingAccount" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/billingAccounts/{billingAccountId}/portalSession": { + "post": { + "x-speakeasy-ignore": true, + "summary": "Create a portal session for a billing account", + "operationId": "createBillingAccountSession", + "tags": [ + "Billing Account" + ], + "parameters": [ + { + "name": "billingAccountId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "redirectUrl" + ], + "properties": { + "redirectUrl": { + "type": "string", + "description": "The URL to redirect to once a portal session is exited.", + "example": "https://dashboard.withampersand.com/the-current-page" + }, + "timeout": { + "type": "integer", + "description": "The number of seconds before the portal session expires.", + "example": 3600 + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "The URL to redirect to in order to start the portal session.", + "example": "https://billing.portal.com/customer/session" + } + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/topics": { + "post": { + "summary": "Create a topic", + "operationId": "createTopic", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the topic. Must contain only letters, numbers, and dashes.", + "example": "system-alerts", + "maxLength": 64 + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Topic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "409": { + "description": "Conflict - A topic with this name already exists in this project. Please choose a different name", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "topic" + }, + "get": { + "summary": "List topics", + "operationId": "listTopics", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "responses": { + "200": { + "description": "List of topics", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Topic" + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/topics/{topicId}": { + "patch": { + "summary": "Update a topic", + "operationId": "updateTopic", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "topicId", + "in": "path", + "required": true, + "description": "The topic ID.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "A human-readable name for the topic.", + "example": "Updated System Alerts" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Topic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "404": { + "description": "Topic not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "409": { + "description": "Conflict - A topic with this name already exists in this project. Please choose a different name", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "updateTopicRequest" + }, + "delete": { + "summary": "Delete a topic", + "operationId": "deleteTopic", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + }, + { + "name": "topicId", + "in": "path", + "required": true, + "description": "The topic ID.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "404": { + "description": "Topic not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/notification-event-topic-routes": { + "post": { + "summary": "Create a notification event-topic route", + "operationId": "createEventTopicRoute", + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "eventType", + "topicId" + ], + "properties": { + "eventType": { + "$ref": "#/components/schemas/NotificationEventType" + }, + "topicId": { + "type": "string", + "description": "The ID of the topic to route events to." + } + } + }, + "examples": { + "route_example": { + "summary": "Create event-topic route", + "value": { + "eventType": "installation.created", + "topicId": "1234567890abcdef" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationEventTopicRoute" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "eventTopicRoute" + }, + "get": { + "summary": "List notification event-topic routes", + "operationId": "listEventTopicRoutes", + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + } + }, + { + "name": "topicId", + "in": "query", + "required": false, + "description": "Filter by topic ID.", + "schema": { + "type": "string" + } + }, + { + "name": "eventType", + "in": "query", + "required": false, + "description": "Filter by notification event type.", + "schema": { + "$ref": "#/components/schemas/NotificationEventType" + } + } + ], + "responses": { + "200": { + "description": "List of event-topic routes", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationEventTopicRoute" + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/notification-event-topic-routes/{routeId}": { + "delete": { + "summary": "Delete a notification event-topic route", + "operationId": "deleteEventTopicRoute", + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + } + }, + { + "name": "routeId", + "in": "path", + "required": true, + "description": "The event-topic route ID.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "404": { + "description": "Route not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/topic-destination-routes": { + "post": { + "summary": "Create a topic destination route", + "operationId": "createTopicDestinationRoute", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + }, + "example": "my-project" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "topicId", + "destinationId" + ], + "properties": { + "topicId": { + "type": "string", + "description": "The ID of the topic." + }, + "destinationId": { + "type": "string", + "description": "The ID of the destination." + } + } + }, + "examples": { + "route_example": { + "summary": "Create topic destination route", + "value": { + "topicId": "1234567890abcdef", + "destinationId": "abcdef1234567890" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDestinationRoute" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + }, + "x-codegen-request-body-name": "topicDestinationRoute" + }, + "get": { + "summary": "List topic destination routes", + "operationId": "listTopicDestinationRoutes", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + } + }, + { + "name": "topicId", + "in": "query", + "required": false, + "description": "Filter by topic ID.", + "schema": { + "type": "string" + } + }, + { + "name": "destinationId", + "in": "query", + "required": false, + "description": "Filter by destination ID.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of topic destination routes", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TopicDestinationRoute" + } + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/topic-destination-routes/{routeId}": { + "delete": { + "summary": "Delete a topic destination route", + "operationId": "deleteTopicDestinationRoute", + "tags": [ + "Destination" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "description": "The Ampersand project ID or project name.", + "schema": { + "type": "string" + } + }, + { + "name": "routeId", + "in": "path", + "required": true, + "description": "The topic destination route ID.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "404": { + "description": "Route not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/jwt-keys": { + "post": { + "summary": "Create a new JWT key", + "description": "Creates a new JWT key for the specified project with RSA public key for token verification", + "operationId": "createJWTKey", + "tags": [ + "JWT Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Ampersand Project ID or name." + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateJWTKeyRequest" + }, + "examples": { + "example1": { + "summary": "Valid RSA JWT key creation", + "value": { + "name": "production-key-1", + "algorithm": "RSA", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41\nfGnJm6gOdrj8ym3rFkEjWT2btf2QisEgQG5WQwTfEUvUNR8JW5FQ0mKJ5I4LhXq6\nV5gN6kSKs2cUdD8Ky7Lj7kqn6I3l3r3F2fK9MFjZ8tU5z4z4yHdF6W2C3k5vf3f\n-----END PUBLIC KEY-----\n" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "JWT key created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JWTKeyResponse" + }, + "examples": { + "example1": { + "summary": "Successful key creation", + "value": { + "kid": "550e8400-e29b-41d4-a716-446655440000" + } + } + } + } + } + }, + "400": { + "description": "Bad request - validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + }, + "examples": { + "invalidAlgorithm": { + "summary": "Unsupported algorithm", + "value": { + "type": "https://httpstatuses.com/400", + "title": "Bad Request", + "status": 400, + "detail": "unsupported algorithm", + "validationIssues": [ + { + "field": "algorithm", + "value": "ECDSA", + "detail": "only RSA algorithm is supported", + "remedy": "use 'RSA' as the algorithm" + } + ] + } + }, + "invalidPublicKey": { + "summary": "Invalid public key format", + "value": { + "type": "https://httpstatuses.com/400", + "title": "Bad Request", + "status": 400, + "detail": "invalid public key", + "validationIssues": [ + { + "field": "publicKeyPem", + "detail": "invalid RSA public key in PEM format", + "remedy": "provide a valid RSA public key in PEM format" + } + ] + } + } + } + } + } + }, + "404": { + "description": "Project not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + }, + "examples": { + "projectNotFound": { + "summary": "Project does not exist", + "value": { + "type": "https://httpstatuses.com/404", + "title": "Not Found", + "status": 404, + "detail": "project not found", + "validationIssues": [ + { + "field": "projectId", + "detail": "project not found", + "remedy": "check the project ID and try again" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "get": { + "summary": "List JWT keys", + "description": "Retrieves all JWT keys for the specified project, with optional filtering for active keys only", + "operationId": "listJWTKeys", + "tags": [ + "JWT Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Ampersand Project ID or name." + }, + { + "name": "active", + "in": "query", + "description": "Filter to only return active JWT keys", + "required": false, + "schema": { + "type": "boolean", + "default": false + }, + "example": true + } + ], + "responses": { + "200": { + "description": "List of JWT keys retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JWTKey" + } + }, + "examples": { + "example1": { + "summary": "Multiple JWT keys", + "value": [ + { + "id": "550e8400-e29b-41d4-a716-446655440000", + "projectId": "123e4567-e89b-12d3-a456-426614174000", + "label": "production-key-1", + "algorithm": "RSA", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41\n-----END PUBLIC KEY-----\n", + "active": true, + "createTime": "2024-01-15T10:30:00Z", + "updateTime": "2024-01-15T10:30:00Z" + }, + { + "id": "550e8400-e29b-41d4-a716-446655440001", + "projectId": "123e4567-e89b-12d3-a456-426614174000", + "label": "development-key-1", + "algorithm": "RSA", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5g6xh6m3iLtUfOqn/W52\n-----END PUBLIC KEY-----\n", + "active": false, + "createTime": "2024-01-10T08:15:00Z", + "updateTime": "2024-01-12T14:20:00Z" + } + ] + }, + "emptyList": { + "summary": "No JWT keys found", + "value": [] + } + } + } + } + }, + "400": { + "description": "Bad request - invalid project ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/projects/{projectIdOrName}/jwt-keys/{keyId}": { + "get": { + "summary": "Get a specific JWT key", + "description": "Retrieves a specific JWT key by its ID within the specified project", + "operationId": "getJWTKey", + "tags": [ + "JWT Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Ampersand Project ID or name." + }, + { + "name": "keyId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The JWT key ID." + } + ], + "responses": { + "200": { + "description": "JWT key retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JWTKey" + }, + "examples": { + "example1": { + "summary": "Single JWT key details", + "value": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "projectId": "123e4567-e89b-12d3-a456-426614174000", + "label": "production-key-1", + "algorithm": "RSA", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41\n-----END PUBLIC KEY-----\n", + "active": true, + "createTime": "2024-01-15T10:30:00Z", + "updateTime": "2024-01-15T10:30:00Z" + } + } + } + } + } + }, + "404": { + "description": "JWT key not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + }, + "examples": { + "keyNotFound": { + "summary": "Key does not exist", + "value": { + "type": "https://httpstatuses.com/404", + "title": "Not Found", + "status": 404, + "detail": "JWT key not found", + "remedy": "check the key ID and project ID are both correct, and try again" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "patch": { + "summary": "Update a JWT key", + "description": "Updates specific fields of a JWT key using field masks. Currently supports updating the 'active' status and 'name' field.", + "operationId": "updateJWTKey", + "tags": [ + "JWT Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Ampersand Project ID or name." + }, + { + "name": "keyId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The JWT key ID." + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PatchJWTKeyRequest" + }, + "examples": { + "deactivateKey": { + "summary": "Deactivate a JWT key", + "value": { + "updateMask": [ + "active" + ], + "jwtKey": { + "active": false + } + } + }, + "renameKey": { + "summary": "Rename a JWT key", + "value": { + "updateMask": [ + "name" + ], + "jwtKey": { + "name": "updated-key-name" + } + } + }, + "updateMultiple": { + "summary": "Update both name and active status", + "value": { + "updateMask": [ + "active", + "name" + ], + "jwtKey": { + "active": false, + "name": "deprecated-key" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "JWT key updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JWTKey" + }, + "examples": { + "example1": { + "summary": "Updated JWT key", + "value": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "projectId": "123e4567-e89b-12d3-a456-426614174000", + "label": "updated-key-name", + "algorithm": "RSA", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41\n-----END PUBLIC KEY-----\n", + "active": false, + "createTime": "2024-01-15T10:30:00Z", + "updateTime": "2024-01-16T15:45:00Z" + } + } + } + } + } + }, + "400": { + "description": "Bad request - invalid update mask or missing project/key ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + }, + "examples": { + "invalidMask": { + "summary": "Invalid update mask", + "value": { + "type": "https://httpstatuses.com/400", + "title": "Bad Request", + "status": 400, + "detail": "Invalid update mask", + "remedy": "Allowed masks: 'active' and 'name'" + } + } + } + } + } + }, + "404": { + "description": "JWT key not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "422": { + "description": "Unprocessable entity - value not found for mask", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + }, + "examples": { + "missingValue": { + "summary": "Missing value for update mask", + "value": { + "type": "https://httpstatuses.com/422", + "title": "Unprocessable Entity", + "status": 422, + "detail": "value not found for mask", + "validationIssues": [ + { + "field": "jwtKey", + "detail": "required field missing for specified mask" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "delete": { + "summary": "Delete a JWT key", + "description": "Permanently deletes a JWT key from the specified project", + "operationId": "deleteJWTKey", + "tags": [ + "JWT Key" + ], + "parameters": [ + { + "name": "projectIdOrName", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Ampersand Project ID or name." + }, + { + "name": "keyId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The JWT key ID." + } + ], + "responses": { + "204": { + "description": "JWT key deleted successfully (no content)" + }, + "404": { + "description": "JWT key not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + }, + "examples": { + "keyNotFound": { + "summary": "Key does not exist", + "value": { + "type": "https://httpstatuses.com/404", + "title": "Not Found", + "status": 404, + "detail": "JWT key not found", + "remedy": "check the key ID and project ID are both correct, and try again" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/claimed-domains": { + "get": { + "operationId": "checkClaimedDomain", + "summary": "Check if a domain is claimed", + "description": "Returns claimed domain information if authenticated user is an owner of the organization that claimed the domain, or if the user's email domain matches the claimed domain.", + "tags": [ + "Org" + ], + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "domain", + "in": "query", + "required": true, + "description": "Accepts an email address, domain name, or URL. The domain will be automatically extracted: for emails, the portion after @ is used (e.g., \"user@example.com\" becomes \"example.com\"); for URLs, the hostname is extracted (e.g., \"https://www.example.com\" becomes \"example.com\").\n", + "schema": { + "type": "string" + }, + "example": "xyz@withampersand.com" + } + ], + "responses": { + "200": { + "description": "Domain claim status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClaimedDomainResponse" + } + } + } + }, + "400": { + "description": "Bad Request - Invalid input", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "404": { + "description": "Domain not claimed", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + }, + "post": { + "operationId": "claimDomain", + "summary": "Claim a domain", + "description": "Claim a domain for an organization. Accepts email, domain, or URL.", + "tags": [ + "Org" + ], + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "domain", + "parentId", + "parentType" + ], + "properties": { + "domain": { + "type": "string", + "description": "Accepts an email address, domain name, or URL. The domain will be automatically extracted: for emails, the portion after @ is used (e.g., \"user@example.com\" becomes \"example.com\"); for URLs, the hostname is extracted (e.g., \"https://www.example.com\" becomes \"example.com\").\n", + "example": "xyz@withampersand.com" + }, + "parentId": { + "type": "string", + "description": "ID of the parent entity claiming the domain", + "example": "orgId" + }, + "parentType": { + "type": "string", + "description": "Type of the parent entity", + "example": "org" + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Domain claimed successfully" + }, + "400": { + "description": "Bad Request - Invalid input", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/InputValidationProblem" + } + } + } + }, + "409": { + "description": "Domain already claimed by another organization", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + }, + "/orgs/{orgId}/claimed-domains": { + "get": { + "operationId": "listOrgClaimedDomains", + "summary": "List organization's claimed domains", + "description": "Get all domains claimed by a specific organization", + "tags": [ + "Org" + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Organization ID", + "example": "orgId" + } + ], + "responses": { + "200": { + "description": "List of claimed domains for the organization", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClaimedDomainResponse" + } + } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + }, + "default": { + "description": "Error", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ApiProblem" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Org": { + "title": "Organization", + "required": [ + "id", + "label", + "createTime", + "defaultTeamId" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The organization ID.", + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + }, + "label": { + "type": "string", + "description": "The organization label.", + "example": "Acme Inc" + }, + "defaultTeamId": { + "type": "string", + "description": "The ID of the Everyone team for the org." + }, + "createTime": { + "type": "string", + "description": "The time at which the organization was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the organization was updated.", + "format": "date-time" + } + } + }, + "Destination": { + "title": "Destination", + "required": [ + "id", + "name", + "type", + "metadata", + "createTime" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The destination ID." + }, + "name": { + "type": "string", + "description": "User-defined name for the destination.", + "example": "leadConvertedWebhook" + }, + "type": { + "type": "string", + "description": "The type of the destination.", + "example": "webhook" + }, + "metadata": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Webhook URL", + "example": "https://webhooks.mailmonkey.com/salesforce-lead-converted" + }, + "headers": { + "$ref": "#/components/schemas/WebhookHeaders" + }, + "streamName": { + "type": "string", + "description": "The name of the Kinesis stream", + "example": "my-data-stream" + }, + "region": { + "type": "string", + "description": "The AWS region for the destination", + "example": "us-east-1" + }, + "partitionKeyTemplate": { + "type": "string", + "description": "Template for generating partition keys", + "example": "{{.integration_id}}" + }, + "bucket": { + "type": "string", + "description": "The name of the S3 bucket", + "example": "ampersand-integration-bucket" + }, + "keyTemplate": { + "type": "string", + "description": "JMESPath template for generating S3 object keys", + "example": "join('/', [metadata.objectName, metadata.operationId])" + }, + "storageClass": { + "type": "string", + "description": "The S3 storage class for written objects (defaults to STANDARD)", + "example": "STANDARD" + } + } + }, + "createTime": { + "type": "string", + "description": "The time the destination was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the destination was updated.", + "format": "date-time" + } + } + }, + "DestinationWithSecrets": { + "title": "DestinationWithSecrets", + "description": "Destination object with secrets field (returned by getDestination when includeSecrets is true)", + "required": [ + "id", + "name", + "type", + "metadata", + "createTime" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The destination ID." + }, + "name": { + "type": "string", + "description": "User-defined name for the destination.", + "example": "leadConvertedWebhook" + }, + "type": { + "type": "string", + "description": "The type of the destination.", + "example": "webhook" + }, + "metadata": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Webhook URL", + "example": "https://webhooks.mailmonkey.com/salesforce-lead-converted" + }, + "headers": { + "$ref": "#/components/schemas/WebhookHeaders" + }, + "streamName": { + "type": "string", + "description": "The name of the Kinesis stream", + "example": "my-data-stream" + }, + "region": { + "type": "string", + "description": "The AWS region for the destination", + "example": "us-east-1" + }, + "partitionKeyTemplate": { + "type": "string", + "description": "Template for generating partition keys", + "example": "{{.integration_id}}" + }, + "bucket": { + "type": "string", + "description": "The name of the S3 bucket", + "example": "ampersand-integration-bucket" + }, + "keyTemplate": { + "type": "string", + "description": "JMESPath template for generating S3 object keys", + "example": "join('/', [metadata.objectName, metadata.operationId])" + }, + "storageClass": { + "type": "string", + "description": "The S3 storage class for written objects (defaults to STANDARD)", + "example": "STANDARD" + } + } + }, + "createTime": { + "type": "string", + "description": "The time the destination was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the destination was updated.", + "format": "date-time" + }, + "secrets": { + "type": "object", + "description": "Destination secrets (only included when includeSecrets is true)", + "properties": { + "webhookSigningKey": { + "type": "string", + "description": "Webhook signing key for the destination (only included for webhook destinations)" + } + } + } + } + }, + "Project": { + "title": "Project", + "required": [ + "appName", + "createTime", + "id", + "name", + "orgId" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier for the project.", + "example": "proj_9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + }, + "name": { + "type": "string", + "description": "The unique name for the project.", + "example": "mailmonkey-staging" + }, + "appName": { + "type": "string", + "description": "The display name of the application, shown to end users during the connection flow.", + "example": "MailMonkey" + }, + "orgId": { + "type": "string", + "description": "The ID of the organization that this project belongs to.", + "example": "9f7c3e2a-61b8-4f5c-8d1a-eb24f3b05d79" + }, + "createTime": { + "type": "string", + "description": "The time the project was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the project was updated.", + "format": "date-time" + }, + "entitlements": { + "type": "object", + "description": "Plan-based feature flags for the project. These are managed by Ampersand and cannot be set via the API.", + "properties": { + "brandingRemoval": { + "type": "object", + "required": [ + "value" + ], + "x-go-type-skip-optional-pointer": true, + "description": "Controls whether Ampersand branding is removed from the embeddable UI components.", + "properties": { + "value": { + "type": "boolean", + "description": "True if Ampersand branding has been removed for this project." + } + } + }, + "logRetentionDays": { + "type": "object", + "required": [ + "value" + ], + "x-go-type-skip-optional-pointer": true, + "description": "The number of days that logs are retained for this project.", + "properties": { + "value": { + "type": "integer", + "description": "The log retention period for this project, in days." + } + } + } + } + } + } + }, + "ProviderApp": { + "title": "Provider App", + "required": [ + "clientId", + "createTime", + "id", + "projectId", + "provider" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The provider app ID.", + "example": "provider-app-123" + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID.", + "example": "project-456" + }, + "externalRef": { + "type": "string", + "description": "The ID used by the provider to identify the app (optional).", + "example": "external-id-123" + }, + "provider": { + "type": "string", + "description": "The SaaS provider that this app connects to.", + "example": "salesforce" + }, + "clientId": { + "type": "string", + "description": "The OAuth client ID for this app.", + "example": "client-id-123" + }, + "scopes": { + "type": "array", + "description": "The OAuth scopes for this app.", + "items": { + "type": "string", + "example": [ + "oauth", + "offline", + "crm.read" + ] + } + }, + "metadata": { + "$ref": "#/components/schemas/ProviderAppMetadata" + }, + "createTime": { + "type": "string", + "description": "The time the provider app was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the provider app was updated.", + "format": "date-time" + } + } + }, + "ProviderAppMetadata": { + "title": "Provider App Metadata", + "type": "object", + "description": "Provider-specific configuration that extends the standard OAuth flow.", + "properties": { + "authQueryParams": { + "type": "object", + "description": "Additional query parameters to include in the OAuth authorization URL (e.g., optional_scope for HubSpot).", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "example": { + "optional_scope": [ + "automation.sequences.read" + ] + } + }, + "providerParams": { + "type": "object", + "description": "Provider-specific string values keyed by names (e.g., packageInstallURL for Salesforce, gcpProjectId and gcpPubSubTopicName for Gmail).", + "additionalProperties": { + "type": "string" + }, + "example": { + "packageInstallURL": "https://login.salesforce.com/packaging/installPackage.apexp?p0=04t123456789", + "gcpProjectId": "my-gcp-project", + "gcpPubSubTopicName": "my-topic" + } + } + } + }, + "Integration": { + "title": "Integration", + "required": [ + "createTime", + "id", + "latestRevision", + "name", + "projectId", + "provider" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The integration ID." + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID.", + "example": "project-456" + }, + "name": { + "type": "string", + "description": "The integration name.", + "example": "read-accounts" + }, + "provider": { + "type": "string", + "description": "The SaaS provider that this integration connects to.", + "example": "salesforce" + }, + "createTime": { + "type": "string", + "description": "The time the integration was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the integration was last updated.", + "format": "date-time" + }, + "latestRevision": { + "$ref": "#/components/schemas/Revision" + } + } + }, + "Revision": { + "title": "Revision", + "required": [ + "content", + "createTime", + "id", + "specVersion" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The revision ID.", + "example": "revision-id-1" + }, + "specVersion": { + "type": "string", + "description": "The spec version string.", + "example": "1.0.0" + }, + "createTime": { + "type": "string", + "description": "The time the revision was created.", + "format": "date-time" + }, + "content": { + "$ref": "#/components/schemas/Integration-2" + } + } + }, + "HydratedRevision": { + "title": "Hydrated Revision", + "required": [ + "content", + "createTime", + "id", + "specVersion" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The revision ID.", + "example": "f0e1d2c3-b4a5-6789-0abc-def123456789" + }, + "specVersion": { + "type": "string", + "description": "The spec version string.", + "example": "1.0.0" + }, + "createTime": { + "type": "string", + "description": "The time the revision was created.", + "format": "date-time" + }, + "content": { + "$ref": "#/components/schemas/HydratedIntegration" + } + } + }, + "Installation": { + "title": "Installation", + "required": [ + "config", + "connection", + "createTime", + "createdBy", + "healthStatus", + "id", + "integrationId", + "projectId" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The installation ID." + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID.", + "example": "project-456" + }, + "integrationId": { + "type": "string", + "description": "The integration ID." + }, + "group": { + "$ref": "#/components/schemas/Group" + }, + "healthStatus": { + "type": "string", + "enum": [ + "healthy", + "unhealthy" + ], + "description": "The health status of the installation.", + "example": "healthy" + }, + "lastOperationStatus": { + "type": "string", + "enum": [ + "success", + "failure", + "in_progress" + ], + "description": "The status of the latest operation for this installation.\n", + "example": "success" + }, + "connection": { + "$ref": "#/components/schemas/Connection" + }, + "createTime": { + "type": "string", + "description": "The time the installation was created.", + "format": "date-time" + }, + "createdBy": { + "type": "string", + "description": "The person who did the installation, in the format of \"consumer:{consumer-id}\".", + "example": "consumer:consumer-123" + }, + "updateTime": { + "type": "string", + "description": "The time the installation was last updated with a new config.", + "format": "date-time" + }, + "config": { + "$ref": "#/components/schemas/Config" + } + } + }, + "JSONPatchOperation": { + "title": "JSON Patch Operation", + "description": "Represents a single JSON Patch operation (RFC 6902).\nOnly supports add, remove, and replace operations for config updates.\n", + "required": [ + "op", + "path" + ], + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "add", + "remove", + "replace" + ], + "description": "The operation to perform.\n- \"add\": Adds a new field or replaces an existing one at the specified path\n- \"remove\": Removes the field at the specified path\n- \"replace\": Replaces the value at the specified path\n", + "example": "replace" + }, + "path": { + "type": "string", + "description": "JSON Pointer path to the field to operate on (RFC 6901).\nAll paths must start with \"/\" (e.g., \"/schedule\", \"/selectedFields/phone\").\n", + "example": "/schedule" + }, + "value": { + "description": "The value to set for add/replace operations.\nNot used for remove operations.\n", + "example": "*/10 * * * *" + } + } + }, + "Config": { + "title": "Config", + "required": [ + "content", + "createTime", + "createdBy", + "id", + "revisionId" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The config ID.", + "example": "config-123" + }, + "revisionId": { + "type": "string", + "description": "The ID of the revision that was current when this config was created or last updated.\n", + "example": "revision-123" + }, + "createTime": { + "type": "string", + "description": "The time the config was created.", + "format": "date-time" + }, + "createdBy": { + "type": "string", + "description": "The person who created the config, in the format of \"consumer:{consumer-id}\" or \"builder:{builder-id}\".", + "example": "builder:builder-123" + }, + "content": { + "$ref": "#/components/schemas/ConfigContent" + } + } + }, + "Connection": { + "title": "Connection", + "required": [ + "id", + "createTime", + "group", + "consumer", + "projectId", + "provider", + "authScheme", + "status" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The connection ID.", + "example": "connection-123" + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID.", + "example": "project-456" + }, + "provider": { + "type": "string", + "description": "The SaaS provider that this Connection is for.", + "example": "salesforce" + }, + "providerApp": { + "$ref": "#/components/schemas/ProviderApp" + }, + "group": { + "$ref": "#/components/schemas/Group" + }, + "consumer": { + "$ref": "#/components/schemas/Consumer" + }, + "providerWorkspaceRef": { + "type": "string", + "description": "If available, the identifier for the provider workspace (e.g. the Salesforce subdomain)", + "example": "provider-workspace-123" + }, + "providerConsumerRef": { + "type": "string", + "description": "If available, the ID that Salesforce/Hubspot uses to identify this user (e.g. Salesforce has IDs in the form of https://login.salesforce.com/id/00D4x0000019CQTEA2/0054x000000orJ4AA)", + "example": "provider-consumer-123" + }, + "createTime": { + "type": "string", + "description": "The time the connection was created.", + "format": "date-time", + "example": "2023-07-13T21:34:44.816354Z" + }, + "updateTime": { + "type": "string", + "description": "The time the connection was last updated.", + "format": "date-time", + "example": "2023-07-13T21:34:44.816354Z" + }, + "authScheme": { + "type": "string", + "description": "The authentication scheme used for this connection.", + "example": "oauth2/authorizationCode", + "enum": [ + "none", + "apiKey", + "basic", + "oauth2/authorizationCode", + "oauth2/authorizationCodePKCE", + "oauth2/clientCredentials", + "oauth2/password" + ] + }, + "status": { + "type": "string", + "description": "The status of the connection.\n- `created`: The connection has just been created or the access token was just refreshed.\n- `working`: The connection has successfully been used to make a request.\n- `bad_credentials`: The connection encountered credential-related issues when making a request, or when attempting to refresh the access token.\n", + "example": "working", + "enum": [ + "created", + "working", + "bad_credentials" + ] + }, + "oauth2AuthorizationCode": { + "$ref": "#/components/schemas/Oauth2AuthorizationCodeTokensOnly" + }, + "apiKey": { + "type": "string", + "description": "The API key used while making the connection.", + "example": "api-key-123" + }, + "providerMetadata": { + "$ref": "#/components/schemas/ProviderMetadata" + } + } + }, + "Oauth2AuthorizationCodeTokensOnly": { + "title": "OAuth2 AuthorizationCode Token", + "type": "object", + "properties": { + "accessToken": { + "type": "object", + "required": [ + "token" + ], + "description": "The access token for the connection.", + "properties": { + "token": { + "type": "string" + }, + "issuedAt": { + "type": "string", + "format": "date-time", + "example": "2024-04-22T18:55:28.456076Z" + }, + "expiresAt": { + "type": "string", + "format": "date-time", + "example": "2024-10-22T18:55:28.456076Z" + } + } + }, + "refreshToken": { + "type": "object", + "required": [ + "token" + ], + "description": "The refresh token to use for the connection.", + "properties": { + "token": { + "type": "string" + }, + "issuedAt": { + "type": "string", + "format": "date-time", + "example": "2024-04-22T18:55:28.456076Z" + }, + "expiresAt": { + "type": "string", + "format": "date-time", + "example": "2024-10-22T18:55:28.456076Z" + } + } + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The scopes for the tokens." + } + } + }, + "Oauth2AuthorizationCode": { + "title": "OAuth2 Authorization Code", + "type": "object", + "properties": { + "accessToken": { + "type": "object", + "required": [ + "token" + ], + "description": "The access token for the connection.", + "properties": { + "token": { + "type": "string" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + }, + "issuedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "refreshToken": { + "type": "object", + "required": [ + "token" + ], + "description": "The refresh token to use for the connection.", + "properties": { + "token": { + "type": "string" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + }, + "issuedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The scopes for the tokens." + } + } + }, + "UpdateConnectionRequest": { + "title": "Update Connection Request", + "description": "Specify which fields to update in `updateMask` and provide corresponding values in `connection`. Fields in `connection` not listed in `updateMask` are ignored.", + "type": "object", + "required": [ + "updateMask", + "connection" + ], + "properties": { + "updateMask": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "providerWorkspaceRef", + "providerMetadata", + "apiKey", + "basicAuth", + "oauth2ClientCredentials", + "oauth2PasswordCredentials" + ] + }, + "description": "Fields to update. Each entry must have a corresponding value in `connection`. Credential fields (`apiKey`, `basicAuth`, `oauth2ClientCredentials`, `oauth2PasswordCredentials`) must match the connection's existing auth scheme.", + "example": [ + "apiKey" + ] + }, + "connection": { + "$ref": "#/components/schemas/ConnectionRequest" + } + } + }, + "ConnectionRequest": { + "title": "Connection Request Body", + "type": "object", + "properties": { + "providerWorkspaceRef": { + "type": "string", + "description": "The ID of the provider workspace that this connection belongs to." + }, + "providerMetadata": { + "$ref": "#/components/schemas/ProviderMetadata" + }, + "groupName": { + "type": "string", + "description": "The name of the user group that has access to this installation." + }, + "groupRef": { + "type": "string", + "description": "The ID of the user group that has access to this installation.", + "example": "group-123" + }, + "consumerName": { + "type": "string", + "description": "The name of the consumer that has access to this installation." + }, + "consumerRef": { + "type": "string", + "description": "The consumer reference." + }, + "provider": { + "type": "string", + "description": "The provider name (e.g. \"salesforce\", \"hubspot\")" + }, + "apiKey": { + "type": "string", + "description": "The API key to use for the connection." + }, + "customAuth": { + "type": "object", + "description": "Values used for custom auth input variables. Most values are strings (API keys, tokens, etc.), but structured values like arrays are also accepted — for example, googleWorkspaceDelegation sends a `scopes` array alongside the service account key.", + "additionalProperties": true, + "example": { + "serviceAccountKey": "base64encodedkey", + "scopes": [ + "https://www.googleapis.com/auth/calendar", + "https://mail.google.com/" + ] + } + }, + "basicAuth": { + "type": "object", + "required": [ + "username", + "password" + ], + "properties": { + "username": { + "type": "string", + "description": "The username to use for the connection." + }, + "password": { + "type": "string", + "description": "The password to use for the connection." + } + } + }, + "oauth2ClientCredentials": { + "type": "object", + "required": [ + "clientId", + "clientSecret" + ], + "properties": { + "clientId": { + "type": "string", + "description": "The client ID to use for the connection." + }, + "clientSecret": { + "type": "string", + "description": "The client secret to use for the connection." + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The scopes for the tokens." + } + } + }, + "oauth2PasswordCredentials": { + "type": "object", + "required": [ + "username", + "password", + "clientId", + "clientSecret" + ], + "properties": { + "username": { + "type": "string", + "description": "The username to use for the connection." + }, + "password": { + "type": "string", + "description": "The password to use for the connection." + }, + "clientId": { + "type": "string", + "description": "The client ID to use for the connection." + }, + "clientSecret": { + "type": "string", + "description": "The client secret to use for the connection." + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The scopes for the tokens." + } + } + }, + "oauth2AuthorizationCode": { + "$ref": "#/components/schemas/Oauth2AuthorizationCode" + } + } + }, + "GenerateConnectionRequest": { + "title": "Generate Connection Request", + "allOf": [ + { + "$ref": "#/components/schemas/ConnectionRequest" + }, + { + "type": "object", + "required": [ + "groupRef", + "consumerRef", + "provider" + ] + } + ] + }, + "Group": { + "title": "Group", + "required": [ + "createTime", + "groupName", + "groupRef", + "projectId" + ], + "type": "object", + "properties": { + "groupRef": { + "type": "string", + "description": "The ID of the user group that has access to this installation.", + "example": "group-123" + }, + "groupName": { + "type": "string", + "description": "The name of the user group that has access to this installation.", + "example": "Super Customer" + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID.", + "example": "project-456" + }, + "createTime": { + "type": "string", + "description": "The time the group was created.", + "format": "date-time", + "example": "2023-07-13T21:34:44.816354Z" + }, + "updateTime": { + "type": "string", + "description": "The time the group was last updated.", + "format": "date-time", + "example": "2023-07-13T21:34:44.816354Z" + } + } + }, + "Consumer": { + "title": "Consumer", + "required": [ + "consumerName", + "consumerRef", + "createTime", + "projectId" + ], + "type": "object", + "properties": { + "consumerRef": { + "type": "string", + "description": "The consumer reference.", + "example": "consumer-123" + }, + "consumerName": { + "type": "string", + "description": "The name of the consumer.", + "example": "Super Customer" + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID.", + "example": "project-456" + }, + "createTime": { + "type": "string", + "description": "The time the consumer was created.", + "format": "date-time", + "example": "2023-07-13T21:34:44.816354Z" + }, + "updateTime": { + "type": "string", + "description": "The time the consumer was last updated.", + "format": "date-time", + "example": "2023-07-13T21:34:44.816354Z" + } + } + }, + "Operation": { + "title": "Operation", + "required": [ + "projectId", + "integrationId", + "installationId", + "configId", + "actionType", + "status", + "id" + ], + "type": "object", + "properties": { + "projectId": { + "type": "string", + "description": "The Ampersand project ID.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "integrationId": { + "type": "string", + "description": "The integration ID." + }, + "configId": { + "type": "string", + "description": "The config ID.", + "example": "a1b2c3d4-e5f6-4789-a012-3456789abcde" + }, + "actionType": { + "type": "string", + "description": "The type of action that was performed (`read`, `write`, or `subscribe`).\n", + "example": "read" + }, + "id": { + "type": "string", + "description": "Unique identifier for this operation. Use this to fetch operation details or list logs for debugging." + }, + "installationId": { + "type": "string", + "description": "The Ampersand installation ID (customer instance) that this operation ran for." + }, + "status": { + "type": "string", + "description": "The status of the operation.\n- `success`: The operation completed successfully\n- `failure`: The operation failed\n- `in_progress`: The operation is currently running\n", + "example": "success" + }, + "result": { + "type": "string", + "description": "A human-readable summary of what the operation accomplished. Examples: `[contact] No new data found`, `Batch write completed (3 succeeded, 1 failed)`. May be absent.\n", + "example": "[contact] No new data found" + }, + "metadata": { + "type": "object", + "description": "Additional operation details (e.g. objects, retry info, read progress, successfulRecordIds).", + "properties": { + "objects": { + "type": "array", + "items": { + "type": "string" + } + }, + "retry": { + "type": "object", + "properties": { + "attempts": { + "type": "integer" + }, + "lastAttempt": { + "type": "string", + "format": "date-time" + }, + "lastNotified": { + "type": "string", + "format": "date-time" + } + } + }, + "progress": { + "type": "object", + "description": "Read progress for the operation, reporting records processed and, where available, the estimated total. Present for all read operations.", + "properties": { + "installationId": { + "type": "string" + }, + "objectName": { + "type": "string" + }, + "operationId": { + "type": "string" + }, + "recordsProcessed": { + "type": "integer" + }, + "recordsEstimatedTotal": { + "type": "integer", + "description": "Only present for some providers (e.g. Salesforce, HubSpot)." + } + } + }, + "successfulRecordIds": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Provider-assigned IDs of successfully created or updated records. Only present for write operations." + } + }, + "example": { + "objects": [ + "contact" + ], + "progress": { + "installationId": "66438162-5299-4669-a41d-85c5a3b1a83e", + "objectName": "contact", + "operationId": "3efc0f0f-4bb9-498f-996c-9893d98ca4b5", + "recordsProcessed": 1250, + "recordsEstimatedTotal": 5000 + } + } + }, + "createTime": { + "type": "string", + "description": "The time the operation was created.", + "format": "date-time", + "example": "2023-07-13T21:34:44.816354Z" + } + } + }, + "BackfillProgress": { + "title": "BackfillProgress", + "type": "object", + "required": [ + "installationId", + "objectName", + "operationId", + "recordsProcessed" + ], + "properties": { + "installationId": { + "type": "string", + "description": "The installation ID." + }, + "objectName": { + "type": "string", + "description": "The object being synced (e.g., contact, account)." + }, + "operationId": { + "type": "string", + "description": "The ID of the backfill operation." + }, + "recordsProcessed": { + "type": "integer", + "description": "The number of records processed so far. Updates as more records are read during the backfill.", + "example": 1250 + }, + "recordsEstimatedTotal": { + "type": "integer", + "description": "The estimated total number of records to process. Only present for Salesforce and HubSpot; other connectors omit this field.", + "example": 5000 + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "When the backfill operation started." + }, + "updateTime": { + "type": "string", + "format": "date-time", + "description": "When progress was last updated." + } + } + }, + "Log": { + "title": "Log", + "type": "object", + "required": [ + "timestamp", + "severity", + "message" + ], + "properties": { + "timestamp": { + "type": "string", + "description": "The time the log was created.", + "example": "2023-07-13T21:34:44.816354Z" + }, + "message": { + "type": "object", + "description": "The log message object.", + "required": [ + "msg" + ], + "properties": { + "msg": { + "type": "string", + "description": "The use-readable message.", + "example": "This is a log message" + }, + "error": { + "type": "string", + "description": "The error message, if there has been an error." + }, + "operation_id": { + "type": "string", + "description": "The operation ID." + }, + "details": { + "type": "object", + "description": "The details of the log.", + "additionalProperties": { + "type": "string" + }, + "example": { + "request": "GET /api/v1/users" + } + } + }, + "additionalProperties": true + }, + "severity": { + "type": "string", + "description": "The severity of the log.", + "example": "DEBUG" + } + } + }, + "SignedUrl": { + "title": "Signed URL", + "type": "object", + "required": [ + "url", + "bucket", + "path" + ], + "properties": { + "url": { + "type": "string", + "description": "The signed URL to upload the zip file to." + }, + "bucket": { + "type": "string", + "description": "The bucket (will match the bucket part of the url)." + }, + "path": { + "type": "string", + "description": "The path (will match the path part of the url)." + } + } + }, + "ApiKeyScopes": { + "title": "API Key Scopes", + "type": "array", + "description": "The scopes for the API key.", + "items": { + "type": "string", + "example": [ + "full", + "frontend" + ] + } + }, + "ApiKeyRequest": { + "title": "API Key Request", + "type": "object", + "required": [ + "label" + ], + "properties": { + "label": { + "type": "string", + "description": "A short name for the API key.", + "example": "MailMonkey API Key" + }, + "scopes": { + "$ref": "#/components/schemas/ApiKeyScopes" + } + } + }, + "ApiKey": { + "title": "API Key", + "type": "object", + "required": [ + "key", + "projectId", + "label", + "scopes" + ], + "properties": { + "key": { + "type": "string", + "description": "The API key.", + "example": "api-key-123" + }, + "label": { + "type": "string", + "description": "A short name for the API key.", + "example": "MailMonkey API Key" + }, + "scopes": { + "$ref": "#/components/schemas/ApiKeyScopes" + }, + "projectId": { + "type": "string", + "description": "The project ID.", + "example": "my-project" + }, + "active": { + "type": "boolean", + "description": "Whether the API key is active.", + "example": true + } + } + }, + "PatchApiKeyRequest": { + "title": "Patch API Key Request", + "type": "object", + "required": [ + "updateMask", + "apiKey" + ], + "properties": { + "updateMask": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field paths specifying which fields to update. Allowed values include:\n- active\n- label\n- scopes\n", + "example": [ + "active", + "label" + ] + }, + "apiKey": { + "type": "object", + "properties": { + "label": { + "type": "string", + "description": "A short name for the API key.", + "example": "MailMonkey API Key" + }, + "active": { + "type": "boolean", + "description": "Whether the API key is active.", + "example": true + }, + "scopes": { + "$ref": "#/components/schemas/ApiKeyScopes" + } + } + } + } + }, + "WebhookHeaders": { + "title": "Webhook Headers", + "type": "object", + "nullable": true, + "description": "Additional headers to add when Ampersand sends a webhook message", + "additionalProperties": { + "type": "string", + "nullable": false + }, + "example": { + "Authorization": "Bearer 1234" + } + }, + "Invite": { + "title": "Invite", + "type": "object", + "required": [ + "id", + "invitedEmail", + "createTime", + "parentId", + "parentType", + "status" + ], + "properties": { + "id": { + "type": "string", + "description": "The invite ID." + }, + "invitedEmail": { + "type": "string", + "description": "The email address of the person invited." + }, + "parentType": { + "type": "string", + "enum": [ + "org" + ], + "description": "The type of entity that the person is invited to." + }, + "parentId": { + "type": "string", + "description": "The ID of the parent (e.g. org ID)." + }, + "status": { + "type": "string", + "description": "The status of the invite.", + "enum": [ + "pending", + "accepted", + "revoked", + "expired" + ] + }, + "createTime": { + "type": "string", + "description": "The time the invite was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the invite was updated.", + "format": "date-time" + } + } + }, + "Builder": { + "title": "Builder", + "type": "object", + "required": [ + "id", + "idpProvider", + "idpRef", + "createTime" + ], + "properties": { + "id": { + "type": "string", + "description": "The builder ID.", + "example": "builder-id-123" + }, + "idpProvider": { + "type": "string", + "description": "The identity provider", + "example": "clerk" + }, + "idpRef": { + "type": "string", + "description": "ID used by the identity provider" + }, + "createTime": { + "type": "string", + "description": "The time that the builder joined Ampersand.", + "format": "date-time" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "fullName": { + "type": "string" + }, + "primaryEmail": { + "type": "string" + } + } + }, + "BillingAccount": { + "title": "Billing Account", + "type": "object", + "required": [ + "id", + "displayName", + "billingProvider", + "billingProviderRef" + ], + "properties": { + "id": { + "type": "string", + "description": "The billing account ID.", + "example": "billing-account-123" + }, + "displayName": { + "type": "string", + "description": "The display name of the billing account.", + "example": "Acme Inc" + }, + "billingProvider": { + "type": "string", + "description": "The billing provider that this account is associated with.", + "example": "stripe" + }, + "billingProviderRef": { + "type": "string", + "description": "The ID used by the billing provider to identify the account.", + "example": "acct_1J2k3l4m5n6o7p8q9r0s" + }, + "createTime": { + "type": "string", + "description": "The time the billing account was created.", + "format": "date-time" + }, + "updateTime": { + "type": "string", + "description": "The time the billing account was last updated.", + "format": "date-time" + } + } + }, + "BuilderInfo": { + "title": "Builder Info", + "type": "object", + "required": [ + "builder", + "projectRoles" + ], + "properties": { + "builder": { + "$ref": "#/components/schemas/Builder" + }, + "projectRoles": { + "type": "object", + "description": "A map of project IDs to project roles for the builder.", + "additionalProperties": { + "type": "object", + "required": [ + "role", + "principalType", + "principalId", + "project" + ], + "properties": { + "role": { + "type": "string", + "description": "The role of the builder in the project.", + "example": "admin" + }, + "principalType": { + "type": "string", + "description": "The type of the principal.", + "enum": [ + "team", + "builder" + ] + }, + "principalId": { + "type": "string", + "description": "The ID of the team or builder.", + "example": "builder-id-123" + }, + "project": { + "$ref": "#/components/schemas/Project" + } + } + } + }, + "orgRole": { + "type": "object", + "required": [ + "role", + "principalType", + "principalId", + "org" + ], + "properties": { + "role": { + "type": "string", + "description": "The role of the builder in the org.", + "example": "admin" + }, + "principalType": { + "type": "string", + "description": "The type of the principal.", + "enum": [ + "team", + "builder" + ] + }, + "principalId": { + "type": "string", + "description": "The ID of the team or builder.", + "example": "builder-id-123" + }, + "org": { + "$ref": "#/components/schemas/Org" + } + } + } + } + }, + "ObjectMetadata": { + "title": "Object Metadata", + "type": "object", + "required": [ + "name", + "fields" + ], + "properties": { + "name": { + "type": "string", + "description": "The provider name of the object", + "example": "contact" + }, + "displayName": { + "type": "string", + "description": "Human-readable name of the object", + "example": "Contact" + }, + "mappedObjectName": { + "type": "string", + "description": "The mapped name of the object as defined in your integration config, if a mapping was applied. Only present when using the installation-scoped metadata endpoint.", + "example": "people" + }, + "fields": { + "type": "object", + "description": "Map of field metadata keyed by field name", + "additionalProperties": { + "$ref": "#/components/schemas/FieldMetadata" + } + } + } + }, + "ProviderMetadata": { + "title": "Provider Metadata", + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ProviderMetadataInfo" + } + }, + "ProviderMetadataInfo": { + "title": "Provider Metadata Info", + "type": "object", + "required": [ + "value", + "source" + ], + "properties": { + "value": { + "type": "string", + "description": "The value of the metadata field", + "example": "1234567890" + }, + "source": { + "type": "string", + "description": "The source of the metadata field", + "enum": [ + "input", + "token", + "provider" + ], + "example": "input" + }, + "displayName": { + "type": "string", + "description": "The human-readable name for the field", + "example": "Account ID" + } + } + }, + "PaginationInfo": { + "title": "Pagination Information", + "type": "object", + "required": [ + "done" + ], + "properties": { + "done": { + "type": "boolean", + "description": "If set to true, this is the last page of results for the given operation. There are no more results & there will be no nextPageToken sent when done is true.", + "example": false + }, + "nextPageToken": { + "type": "string", + "description": "If present, set this value against your 'pageToken' query parameter in the next API call, which will retrieve the next set of results.", + "example": "Q9JT+2qfys28V4ODN+UayA==" + } + } + }, + "UpdateMask": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field paths specifying which fields to update.\nUses dot notation for nested fields (e.g., \"config.revision\", \"metadata.tags\").\n\n**Field Path Rules:**\n- Use dot notation for nested objects: `parent.child.field`\n- Escape special characters: `field\\.with\\.dots`, `field\\:with\\:colons`\n- Array elements not directly addressable\n- Object names can be specified directly (e.g., \"config.content.read.objects.contacts\")\n- The * operator in paths like \"config.content.read.objects.*\" allows you to specify any object name\n - Example: \"config.content.read.objects.*\" pattern allows \"config.content.read.objects.contacts\", \"config.content.read.objects.leads\", etc.\n", + "example": [ + "name", + "config.content.read.objects.contacts", + "config.content.write.objects.leads" + ] + }, + "CreateJWTKeyRequest": { + "type": "object", + "required": [ + "label", + "algorithm", + "publicKeyPem" + ], + "properties": { + "label": { + "type": "string", + "description": "Human-readable label for the JWT key", + "minLength": 1, + "maxLength": 255, + "example": "production-key-1" + }, + "algorithm": { + "type": "string", + "description": "The cryptographic JWT signing algorithm (currently only RS256 is supported)", + "enum": [ + "RS256" + ], + "example": "RS256" + }, + "publicKeyPem": { + "type": "string", + "description": "RSA public key in PEM format for JWT signature verification", + "format": "pem", + "example": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41\nfGnJm6gOdrj8ym3rFkEjWT2btf2QisEgQG5WQwTfEUvUNR8JW5FQ0mKJ5I4LhXq6\nV5gN6kSKs2cUdD8Ky7Lj7kqn6I3l3r3F2fK9MFjZ8tU5z4z4yHdF6W2C3k5vf3f\n-----END PUBLIC KEY-----\n" + } + } + }, + "JWTKeyResponse": { + "type": "object", + "required": [ + "kid" + ], + "properties": { + "kid": { + "type": "string", + "format": "uuid", + "description": "The unique key identifier (key ID) for the created JWT key", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + } + }, + "JWTKey": { + "type": "object", + "required": [ + "id", + "projectId", + "label", + "algorithm", + "publicKeyPem", + "active", + "createTime", + "updateTime" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the JWT key", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "projectId": { + "type": "string", + "format": "uuid", + "description": "The project this JWT key belongs to", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "label": { + "type": "string", + "description": "Human-readable name for the JWT key", + "example": "production-key-1" + }, + "algorithm": { + "type": "string", + "description": "The cryptographic algorithm used", + "enum": [ + "RSA" + ], + "example": "RSA" + }, + "publicKeyPem": { + "type": "string", + "description": "RSA public key in PEM format", + "format": "pem", + "example": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41\n-----END PUBLIC KEY-----\n" + }, + "active": { + "type": "boolean", + "description": "Whether the JWT key is currently active and can be used for verification", + "example": true + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the JWT key was created", + "example": "2024-01-15T10:30:00Z" + }, + "updateTime": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the JWT key was last updated", + "example": "2024-01-15T10:30:00Z" + } + } + }, + "PatchJWTKeyRequest": { + "type": "object", + "required": [ + "updateMask", + "jwtKey" + ], + "properties": { + "updateMask": { + "type": "array", + "description": "List of field paths to update (currently supports 'active' and 'name')", + "items": { + "type": "string", + "enum": [ + "active", + "label" + ] + }, + "minItems": 1, + "example": [ + "active", + "label" + ] + }, + "jwtKey": { + "type": "object", + "description": "Object containing the fields to update with their new values", + "additionalProperties": true, + "properties": { + "active": { + "type": "boolean", + "description": "New active status for the JWT key", + "example": false + }, + "label": { + "type": "string", + "description": "New label for the JWT key", + "example": "updated-key-name" + } + }, + "example": { + "active": false, + "name": "updated-key-name" + } + } + } + }, + "UpsertMetadataRequest": { + "type": "object", + "description": "Request payload for upserting metadata (fields only)", + "properties": { + "groupRef": { + "type": "string", + "description": "The ID that your app uses to identify the group of users for this request.", + "example": "group-123" + }, + "fields": { + "type": "object", + "description": "Maps object names to field definitions", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldDefinition" + } + } + } + }, + "required": [ + "groupRef", + "fields" + ] + }, + "UpsertMetadataResponse": { + "type": "object", + "description": "Response containing results for all created/updated fields", + "properties": { + "success": { + "type": "boolean", + "description": "Indicates if the upsert operation was successful" + }, + "fields": { + "type": "object", + "description": "Maps object name -> field name -> upsert result", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/FieldUpsertResult" + } + } + } + }, + "required": [ + "success", + "fields" + ] + }, + "FieldDefinition": { + "type": "object", + "description": "Field definition for creating or updating custom fields", + "properties": { + "fieldName": { + "type": "string", + "description": "The identifier of the field", + "example": "My_Custom_Field" + }, + "displayName": { + "type": "string", + "description": "The human-readable name of the field", + "example": "My Custom Field" + }, + "description": { + "type": "string", + "description": "Optional description of the field" + }, + "valueType": { + "type": "string", + "description": "The data type of the field. Valid values are string, boolean, date, datetime, singleSelect, multiSelect, int, float, reference", + "example": "string" + }, + "required": { + "type": "boolean", + "description": "Indicates if the field is required" + }, + "unique": { + "type": "boolean", + "description": "Indicates if the field must be unique across all records" + }, + "indexed": { + "type": "boolean", + "description": "Indicates if the field should be indexed for faster search" + }, + "stringOptions": { + "$ref": "#/components/schemas/StringFieldOptions" + }, + "numericOptions": { + "$ref": "#/components/schemas/NumericFieldOptions" + }, + "association": { + "$ref": "#/components/schemas/AssociationDefinition" + } + }, + "required": [ + "fieldName", + "displayName", + "valueType" + ] + }, + "StringFieldOptions": { + "type": "object", + "description": "Additional options for string fields", + "properties": { + "length": { + "type": "integer", + "description": "Maximum length of the string field" + }, + "pattern": { + "type": "string", + "description": "Regex pattern that the string field value must match" + }, + "values": { + "type": "array", + "description": "List of allowed values for enum fields", + "items": { + "type": "string" + } + }, + "valuesRestricted": { + "type": "boolean", + "description": "Indicates if the field value must be limited to what's in Values" + }, + "defaultValue": { + "type": "string", + "description": "Default value for the field" + } + } + }, + "NumericFieldOptions": { + "type": "object", + "description": "Additional options for numeric fields", + "properties": { + "precision": { + "type": "integer", + "description": "Total number of digits (for decimal types)" + }, + "scale": { + "type": "integer", + "description": "Number of digits to the right of the decimal point (for decimal types)" + }, + "min": { + "type": "number", + "description": "Minimum value for numeric fields" + }, + "max": { + "type": "number", + "description": "Maximum value for numeric fields" + }, + "defaultValue": { + "type": "number", + "description": "Default value for the field" + } + } + }, + "AssociationDefinition": { + "type": "object", + "description": "Relationship information for a field to another object", + "properties": { + "associationType": { + "type": "string", + "description": "High-level association variety (e.g., 'foreignKey', 'lookup', 'ref')", + "example": "foreignKey" + }, + "targetObject": { + "type": "string", + "description": "Name of the referenced/parent object", + "example": "Account" + }, + "targetField": { + "type": "string", + "description": "Name of the referenced field on the target object" + }, + "cardinality": { + "type": "string", + "description": "Association cardinality from the referencing field's perspective", + "example": "many-to-one" + }, + "onDelete": { + "type": "string", + "description": "Behavior upon foreign object deletion", + "example": "setNull" + }, + "required": { + "type": "boolean", + "description": "If true, a referenced record must exist" + }, + "reverseLookupFieldName": { + "type": "string", + "description": "Optional inverse relationship/property name exposed on the target object" + }, + "labels": { + "$ref": "#/components/schemas/AssociationLabels" + } + }, + "required": [ + "associationType", + "targetObject" + ] + }, + "AssociationLabels": { + "type": "object", + "description": "UI labels for an association", + "properties": { + "singular": { + "type": "string", + "description": "Singular display label" + }, + "plural": { + "type": "string", + "description": "Plural display label" + } + } + }, + "FieldUpsertResult": { + "type": "object", + "description": "Result of an upsert operation for a single field", + "properties": { + "fieldName": { + "type": "string", + "description": "Name of the field" + }, + "action": { + "type": "string", + "description": "Action taken (create, update, none)" + }, + "metadata": { + "type": "object", + "description": "Provider-specific metadata about the field", + "additionalProperties": true + }, + "warnings": { + "type": "array", + "description": "Warnings that occurred during the upsert operation", + "items": { + "type": "string" + } + } + }, + "required": [ + "fieldName", + "action" + ] + }, + "ClaimedDomainResponse": { + "type": "object", + "required": [ + "id", + "parentType", + "parentId", + "domain" + ], + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the claimed domain", + "example": "00000000-0000-0000-0000-000000000001" + }, + "parentType": { + "type": "string", + "description": "Type of the parent entity that claimed the domain", + "example": "org" + }, + "parentId": { + "type": "string", + "description": "ID of the parent entity that claimed the domain", + "example": "00000000-0000-0000-0000-000000000001" + }, + "domain": { + "type": "string", + "description": "The normalized domain name", + "example": "xyz.com" + } + } + }, + "Topic": { + "title": "Topic", + "required": [ + "id", + "name", + "projectId", + "createTime" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The topic ID." + }, + "name": { + "type": "string", + "description": "The name of the topic. Must contain only letters, numbers, and dashes.", + "example": "system-alerts", + "maxLength": 64 + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID." + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "The time when the topic was created." + }, + "updateTime": { + "type": "string", + "format": "date-time", + "description": "The time when the topic was last updated." + } + } + }, + "NotificationEventTopicRoute": { + "title": "Notification Event Topic Route", + "required": [ + "id", + "eventType", + "topicId", + "projectId", + "createTime" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The event-topic route ID." + }, + "eventType": { + "$ref": "#/components/schemas/NotificationEventType" + }, + "topicId": { + "type": "string", + "description": "The ID of the topic to route events to." + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID." + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "The time when the event-topic route was created." + }, + "updateTime": { + "type": "string", + "format": "date-time", + "description": "The time when the event-topic route was last updated." + } + } + }, + "NotificationEventType": { + "type": "string", + "description": "The type of notification event.", + "enum": [ + "connection.created", + "connection.error", + "connection.refreshed", + "connection.deleted", + "installation.created", + "installation.updated", + "installation.deleted", + "read.schedule.paused", + "read.backfill.done", + "read.triggered.done", + "read.triggered.error", + "write.async.done", + "subscribe.create.error", + "destination.webhook.disabled" + ] + }, + "TopicDestinationRoute": { + "title": "Topic Destination Route", + "required": [ + "id", + "topicId", + "destinationId", + "projectId", + "createTime" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The topic destination route ID." + }, + "topicId": { + "type": "string", + "description": "The ID of the topic." + }, + "destinationId": { + "type": "string", + "description": "The ID of the destination." + }, + "projectId": { + "type": "string", + "description": "The Ampersand project ID." + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "The time when the topic destination route was created." + } + } + }, + "Problem": { + "title": "Problem", + "description": "A Problem Details object (RFC 9457).\n\nAdditional properties specific to the problem type may be present.\n", + "type": "object", + "properties": { + "type": { + "type": "string", + "format": "uri", + "description": "An absolute URI that identifies the problem type", + "default": "about:blank" + }, + "href": { + "type": "string", + "format": "uri", + "description": "An absolute URI that, when dereferenced, provides human-readable documentation for the problem type (e.g. using HTML)." + }, + "title": { + "type": "string", + "description": "A short summary of the problem type. Written in English and readable for engineers (usually not suited for non technical stakeholders and not localized).", + "example": "Service Unavailable" + }, + "status": { + "type": "integer", + "format": "int32", + "description": "The HTTP status code generated by the origin server for this occurrence of the problem.", + "minimum": 400, + "maximum": 600, + "exclusiveMaximum": true, + "example": 503 + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem" + }, + "instance": { + "type": "string", + "format": "uri", + "description": "An absolute URI that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + } + }, + "example": { + "type": "urn:problem-type:exampleOrganization:exampleProblem", + "href": "https://www.belgif.be/specification/rest/api-guide/#standardized-problem-types", + "title": "Description of the type of problem that occurred", + "status": 400, + "detail": "Description of specific occurrence of the problem", + "instance": "urn:uuid:123e4567-e89b-12d3-a456-426614174000" + } + }, + "ApiProblem": { + "title": "API Problem", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Problem" + } + ], + "properties": { + "subsystem": { + "type": "string", + "description": "The subsystem that generated the problem", + "example": "api" + }, + "time": { + "type": "string", + "format": "date-time", + "description": "The time the problem occurred, formatted as RFC-3339", + "example": "2024-04-22T18:55:28.456076Z" + }, + "requestId": { + "type": "string", + "description": "A unique identifier for the request, useful for debugging", + "example": "89eb1ffb-2a54-4105-aaae-7bf990f1aa69#87715" + }, + "causes": { + "type": "array", + "items": { + "type": "string", + "description": "A brief description of something which caused the problem", + "example": "database connection failed" + }, + "example": [ + "database connection failed", + "database query failed", + "unable to fetch user" + ], + "description": "A list of problems that caused this problem. This can be used to represent multiple\nroot causes. There is no guaranteed ordering of the causes.\n" + }, + "remedy": { + "type": "string", + "description": "A brief description of how to resolve the problem", + "example": "Shorten your input to be under 100 characters" + }, + "supportEmail": { + "type": "string", + "format": "email", + "description": "An email address to contact for support", + "example": "support@withampersand.com" + }, + "supportPhone": { + "type": "string", + "description": "A phone number to contact for support", + "example": "+1-555-555-5555" + }, + "supportUrl": { + "type": "string", + "format": "uri", + "description": "A URL to contact for support", + "example": "https://withampersand.com/support" + }, + "retryable": { + "type": "boolean", + "description": "Whether the request can be retried", + "example": false + }, + "retryAfter": { + "type": "string", + "format": "date-time", + "description": "A timestamp after which the request can be retried, formatted as RFC-3339", + "example": "2024-04-22T18:55:28.456076Z" + }, + "context": { + "type": "object", + "description": "Additional context for the problem", + "additionalProperties": true, + "example": { + "name": "Rick Sanchez" + } + } + } + }, + "InputValidationIssue": { + "title": "Input Validation Issue", + "type": "object", + "description": "An issue detected during input validation.\n", + "allOf": [ + { + "$ref": "#/components/schemas/ApiProblem" + } + ], + "properties": { + "in": { + "type": "string", + "description": "The location of the invalid input", + "enum": [ + "body", + "header", + "path", + "query" + ] + }, + "name": { + "type": "string", + "description": "The name of the invalid input" + }, + "value": { + "description": "The value of the erroneous input" + } + } + }, + "InputValidationProblem": { + "title": "Input Validation Problem", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/ApiProblem" + } + ], + "properties": { + "issues": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InputValidationIssue" + } + } + }, + "example": { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "The input message is incorrect", + "instance": "123456-1234-1235-4567489798", + "issues": [ + { + "type": "about:blank", + "detail": "exampleNumericProperty should be numeric", + "in": "path", + "name": "exampleNumericProperty", + "value": "abc" + }, + { + "type": "about:blank", + "title": "Input isn't valid with respect to schema", + "detail": "examplePropertyWithPattern a2345678901 doesn't match pattern '^\\d{11}$'", + "in": "body", + "name": "items[0].examplePropertyWithPattern", + "value": "a2345678901" + } + ] + } + }, + "IntegrationFieldExistent": { + "title": "Integration Field Existent", + "type": "object", + "required": [ + "fieldName" + ], + "properties": { + "fieldName": { + "type": "string" + }, + "mapToName": { + "type": "string", + "description": "The field name to map to.", + "example": "account_id", + "x-go-type-skip-optional-pointer": true + }, + "mapToDisplayName": { + "type": "string", + "description": "The display name to map to.", + "example": "Account ID", + "x-go-type-skip-optional-pointer": true + } + } + }, + "IntegrationFieldMapping": { + "title": "Integration Field Mapping", + "type": "object", + "required": [ + "mapToName" + ], + "properties": { + "mapToName": { + "type": "string" + }, + "mapToDisplayName": { + "type": "string" + }, + "default": { + "type": "string" + }, + "prompt": { + "type": "string" + } + } + }, + "IntegrationField": { + "title": "Integration Field", + "oneOf": [ + { + "$ref": "#/components/schemas/IntegrationFieldExistent" + }, + { + "$ref": "#/components/schemas/IntegrationFieldMapping" + } + ] + }, + "OptionalFieldsAutoOption": { + "title": "Optional Fields Auto Option", + "type": "string", + "enum": [ + "all" + ] + }, + "DefaultPeriod": { + "title": "Default Period", + "type": "object", + "properties": { + "days": { + "type": "integer", + "description": "Number of days in past to backfill from. 0 is no backfill. e.g) if 10, then backfill last 10 days of data. Required if fullHistory is not set.", + "minimum": 0, + "example": 30, + "x-oapi-codegen-extra-tags": { + "validate": "required_without=FullHistory,omitempty,min=0" + } + }, + "fullHistory": { + "type": "boolean", + "description": "If true, backfill all history. Required if days is not set.", + "example": false, + "x-oapi-codegen-extra-tags": { + "validate": "required_without=Days" + } + } + } + }, + "Backfill": { + "title": "Backfill", + "type": "object", + "required": [ + "defaultPeriod" + ], + "properties": { + "defaultPeriod": { + "$ref": "#/components/schemas/DefaultPeriod" + } + } + }, + "Delivery": { + "title": "Delivery", + "type": "object", + "properties": { + "mode": { + "type": "string", + "default": "auto", + "enum": [ + "onRequest", + "auto" + ], + "description": "The data delivery mode for this object. If not specified, defaults to automatic." + }, + "pageSize": { + "type": "integer", + "description": "The number of records to receive per data delivery.", + "minimum": 50, + "maximum": 500 + } + } + }, + "IntegrationObject": { + "title": "Integration Object", + "type": "object", + "required": [ + "objectName", + "destination", + "schedule" + ], + "properties": { + "objectName": { + "type": "string" + }, + "destination": { + "type": "string", + "x-go-type-skip-optional-pointer": true + }, + "schedule": { + "type": "string", + "x-go-type-skip-optional-pointer": true + }, + "mapToName": { + "type": "string", + "description": "An object name to map to.", + "example": "people", + "x-go-type-skip-optional-pointer": true + }, + "mapToDisplayName": { + "type": "string", + "description": "A display name to map to.", + "example": "People", + "x-go-type-skip-optional-pointer": true + }, + "requiredFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntegrationField" + } + }, + "optionalFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntegrationField" + } + }, + "optionalFieldsAuto": { + "$ref": "#/components/schemas/OptionalFieldsAutoOption" + }, + "backfill": { + "$ref": "#/components/schemas/Backfill" + }, + "delivery": { + "$ref": "#/components/schemas/Delivery" + }, + "enabled": { + "type": "string", + "description": "If set to `always`, the integration will automatically install upon user connection and skip the user field selection step.", + "enum": [ + "always" + ], + "x-go-type-skip-optional-pointer": true + } + } + }, + "IntegrationRead": { + "title": "Read Integration", + "type": "object", + "properties": { + "objects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntegrationObject" + } + } + } + }, + "ValueDefaults": { + "title": "Value Defaults", + "type": "object", + "description": "Configuration to set default write values for object fields.", + "properties": { + "allowAnyFields": { + "type": "boolean", + "description": "If true, users can set default values for any field.", + "example": true + } + } + }, + "IntegrationWriteObject": { + "title": "Integration Write Object", + "type": "object", + "required": [ + "objectName" + ], + "properties": { + "objectName": { + "type": "string" + }, + "inheritMapping": { + "type": "boolean", + "description": "If true, the write object will inherit the mapping from the read object. If false, the write object will have no mapping.", + "example": true + }, + "valueDefaults": { + "$ref": "#/components/schemas/ValueDefaults" + } + } + }, + "IntegrationWrite": { + "title": "Write Integration", + "type": "object", + "properties": { + "objects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntegrationWriteObject" + } + } + } + }, + "IntegrationProxy": { + "title": "Proxy Integration", + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "useModule": { + "type": "boolean", + "description": "Default is false. If this is set to true, the base URL for the proxy action will be the module's base URL. Otherwise, it is assumed that the base URL is the provider's root base URL." + } + } + }, + "CreateEvent": { + "type": "object", + "properties": { + "enabled": { + "type": "string", + "description": "If always, the integration will subscribe to create events by default.", + "enum": [ + "always" + ] + } + } + }, + "UpdateEvent": { + "type": "object", + "properties": { + "enabled": { + "type": "string", + "description": "If always, the integration will subscribe to update events by default.", + "enum": [ + "always" + ] + }, + "watchFieldsAuto": { + "type": "string", + "description": "If `all`, the integration will watch all fields for updates. If `selected`, the integration will watch only the fields that are selected by the user. If `inheritFieldsAndMapping` is true for Subscribe action, the integration will watch the selected fields from read action that are selected by the user.", + "enum": [ + "all", + "selected" + ], + "example": "all" + }, + "requiredWatchFields": { + "type": "array", + "items": { + "type": "string", + "description": "The fields that are required to be watched for updates.", + "example": [ + "name", + "domain" + ] + } + } + } + }, + "DeleteEvent": { + "type": "object", + "properties": { + "enabled": { + "type": "string", + "description": "If always, the integration will subscribe to delete events by default.", + "enum": [ + "always" + ] + } + } + }, + "AssociationChangeEvent": { + "type": "object", + "properties": { + "enabled": { + "type": "string", + "description": "If always, the integration will subscribe to association change events.", + "enum": [ + "always" + ] + }, + "includeFullRecords": { + "type": "boolean", + "description": "If true, the integration will include full records in the event payload." + } + } + }, + "OtherEvents": { + "type": "array", + "items": { + "type": "string", + "description": "Non-standard events that the integration will subscribe to.", + "example": [ + "object.merged", + "object.restored" + ] + } + }, + "IntegrationSubscribeObject": { + "title": "Integration Subscribe Object", + "type": "object", + "required": [ + "objectName", + "destination" + ], + "properties": { + "objectName": { + "type": "string" + }, + "destination": { + "type": "string" + }, + "inheritFieldsAndMapping": { + "type": "boolean", + "x-go-type-skip-optional-pointer": true, + "description": "If true, the integration will inherit the fields and mapping from the read object.", + "example": true + }, + "createEvent": { + "$ref": "#/components/schemas/CreateEvent" + }, + "updateEvent": { + "$ref": "#/components/schemas/UpdateEvent" + }, + "deleteEvent": { + "$ref": "#/components/schemas/DeleteEvent" + }, + "associationChangeEvent": { + "$ref": "#/components/schemas/AssociationChangeEvent" + }, + "otherEvents": { + "$ref": "#/components/schemas/OtherEvents" + } + } + }, + "IntegrationSubscribe": { + "title": "Subscribe Integration", + "type": "object", + "properties": { + "objects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntegrationSubscribeObject" + } + } + } + }, + "FieldCreatedEvent": { + "title": "Field Created Event", + "type": "object", + "description": "Configuration for detecting when new fields are created.", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "string", + "description": "If always, the integration will monitor for new fields by default.", + "enum": [ + "always" + ] + } + } + }, + "FieldDeletedEvent": { + "title": "Field Deleted Event", + "type": "object", + "description": "Configuration for detecting when fields are deleted.", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "string", + "description": "If always, the integration will monitor for deleted fields by default.", + "enum": [ + "always" + ] + } + } + }, + "FieldChangedEvent": { + "title": "Field Changed Event", + "type": "object", + "description": "Configuration for detecting when fields are changed.", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "string", + "description": "If always, the integration will monitor for field changes by default.", + "enum": [ + "always" + ] + } + } + }, + "WatchSchemaAllObjects": { + "title": "Watch Schema All Objects", + "type": "object", + "description": "Schema change event configuration for all objects in the integration.", + "properties": { + "fieldCreated": { + "$ref": "#/components/schemas/FieldCreatedEvent" + }, + "fieldDeleted": { + "$ref": "#/components/schemas/FieldDeletedEvent" + }, + "fieldChanged": { + "$ref": "#/components/schemas/FieldChangedEvent" + } + } + }, + "WatchSchema": { + "title": "Provider schema watch", + "type": "object", + "description": "Configuration for monitoring provider schema changes.", + "required": [ + "destination", + "allObjects" + ], + "properties": { + "destination": { + "type": "string", + "description": "The destination to send schema change notifications to.", + "example": "fieldWatchStream", + "x-go-type-skip-optional-pointer": true + }, + "schedule": { + "type": "string", + "description": "Cron schedule for checking schema changes. Minimum frequency is once per hour. Defaults to once a day.", + "default": "0 */24 * * *", + "example": "0 */6 * * *", + "x-go-type-skip-optional-pointer": true + }, + "allObjects": { + "$ref": "#/components/schemas/WatchSchemaAllObjects" + } + } + }, + "Integration-2": { + "title": "Integration", + "type": "object", + "required": [ + "name", + "provider" + ], + "properties": { + "name": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "displayName": { + "type": "string", + "x-go-type-skip-optional-pointer": true + }, + "module": { + "type": "string", + "x-go-type-skip-optional-pointer": true + }, + "read": { + "$ref": "#/components/schemas/IntegrationRead" + }, + "write": { + "$ref": "#/components/schemas/IntegrationWrite" + }, + "proxy": { + "$ref": "#/components/schemas/IntegrationProxy" + }, + "subscribe": { + "$ref": "#/components/schemas/IntegrationSubscribe" + }, + "watchSchema": { + "$ref": "#/components/schemas/WatchSchema" + } + } + }, + "HydratedIntegrationFieldExistent": { + "type": "object", + "required": [ + "fieldName", + "displayName" + ], + "properties": { + "fieldName": { + "type": "string", + "example": "billingcity" + }, + "displayName": { + "type": "string", + "example": "Billing City" + }, + "mapToName": { + "type": "string", + "description": "The field name to map to in the destination.", + "example": "billing_city", + "x-go-type-skip-optional-pointer": true + }, + "mapToDisplayName": { + "type": "string", + "description": "The display name to map to in the destination.", + "example": "Billing City", + "x-go-type-skip-optional-pointer": true + } + } + }, + "HydratedIntegrationField": { + "title": "Hydrated Integration Field", + "oneOf": [ + { + "$ref": "#/components/schemas/HydratedIntegrationFieldExistent" + }, + { + "$ref": "#/components/schemas/IntegrationFieldMapping" + } + ] + }, + "FieldValue": { + "title": "Field Value", + "type": "object", + "required": [ + "value", + "displayValue" + ], + "description": "Represents a field value", + "properties": { + "value": { + "type": "string", + "description": "The internal value used by the system", + "example": "outbound" + }, + "displayValue": { + "type": "string", + "description": "The human-readable display value", + "example": "Outbound Campaign" + } + } + }, + "FieldMetadata": { + "title": "Field Metadata", + "type": "object", + "description": "Metadata about a field. Please note that different providers have different levels of support for field metadata. Please reach out to support@withampersand.com if need expanded support for a particular provider.", + "required": [ + "fieldName", + "displayName" + ], + "properties": { + "fieldName": { + "type": "string", + "description": "The name of the field from the provider API.", + "example": "accountid" + }, + "displayName": { + "type": "string", + "description": "The display name of the field from the provider API.", + "example": "Account ID" + }, + "valueType": { + "type": "string", + "description": "A normalized field type", + "enum": [ + "string", + "boolean", + "singleSelect", + "multiSelect", + "date", + "datetime", + "int", + "float", + "reference", + "other" + ], + "x-go-type-skip-optional-pointer": true + }, + "providerType": { + "type": "string", + "description": "Raw field type from the provider API.", + "example": "timestamp", + "x-go-type-skip-optional-pointer": true + }, + "readOnly": { + "type": "boolean", + "description": "Whether the field is read-only.", + "example": false + }, + "isCustom": { + "type": "boolean", + "description": "Whether the field is custom field.", + "example": false + }, + "isRequired": { + "type": "boolean", + "description": "Whether the field is required when creating a new record.", + "example": false + }, + "referenceTo": { + "type": "array", + "description": "The list of object types this field references. Only applicable if the providerType is a lookup/reference field.", + "x-go-type-skip-optional-pointer": true, + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "description": "If the valueType is singleSelect or multiSelect, this is a list of possible values", + "x-go-type-skip-optional-pointer": true, + "items": { + "$ref": "#/components/schemas/FieldValue" + } + } + } + }, + "HydratedIntegrationObject": { + "title": "Hydrated Integration Object", + "type": "object", + "required": [ + "objectName", + "displayName", + "destination", + "schedule" + ], + "properties": { + "error": { + "type": "string", + "description": "Error message if there was an issue hydrating this object.", + "x-go-type-skip-optional-pointer": true + }, + "objectName": { + "type": "string", + "example": "account" + }, + "displayName": { + "type": "string", + "example": "Account" + }, + "mapToName": { + "type": "string", + "description": "An object name to map to.", + "example": "accounts", + "x-go-type-skip-optional-pointer": true + }, + "mapToDisplayName": { + "type": "string", + "description": "A display name to map to.", + "example": "Accounts", + "x-go-type-skip-optional-pointer": true + }, + "destination": { + "type": "string", + "example": "accountWebhook" + }, + "schedule": { + "type": "string", + "example": "*/10 * * * *" + }, + "requiredFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HydratedIntegrationField" + } + }, + "optionalFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HydratedIntegrationField" + } + }, + "optionalFieldsAuto": { + "$ref": "#/components/schemas/OptionalFieldsAutoOption" + }, + "allFieldsMetadata": { + "description": "This is a map of all fields on the object including their metadata (such as display name and type), the keys of the map are the field names.", + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/FieldMetadata" + }, + "example": { + "name": { + "fieldName": "name", + "displayName": "Account Name", + "valueType": "string", + "providerType": "string", + "readOnly": false, + "isCustom": false, + "isRequired": true + }, + "type": { + "fieldName": "type", + "displayName": "Account Type", + "valueType": "singleSelect", + "providerType": "picklist", + "readOnly": false, + "isCustom": false, + "isRequired": false, + "values": [ + { + "value": "prospect", + "displayValue": "Prospect" + }, + { + "value": "customer", + "displayValue": "Customer - Direct" + } + ] + } + } + }, + "allFields": { + "description": "This is a list of all fields on the object for a particular SaaS instance, including their display names. Prefer using allFieldsMetadata instead.", + "type": "array", + "deprecated": true, + "items": { + "$ref": "#/components/schemas/HydratedIntegrationField" + } + }, + "backfill": { + "$ref": "#/components/schemas/Backfill" + } + } + }, + "HydratedIntegrationRead": { + "title": "Hydrated Read Integration", + "type": "object", + "properties": { + "objects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HydratedIntegrationObject" + } + } + } + }, + "HydratedIntegrationWriteObject": { + "type": "object", + "required": [ + "objectName", + "displayName" + ], + "properties": { + "objectName": { + "type": "string", + "example": "account" + }, + "displayName": { + "type": "string", + "example": "Account" + }, + "valueDefaults": { + "$ref": "#/components/schemas/ValueDefaults" + } + } + }, + "HydratedIntegrationWrite": { + "type": "object", + "properties": { + "objects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HydratedIntegrationWriteObject" + } + } + } + }, + "HydratedIntegrationProxy": { + "title": "Hydrated Proxy Integration", + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "useModule": { + "type": "boolean", + "description": "Default is false. If this is set to true, the base URL for the proxy action will be the module's base URL. Otherwise, it is assumed that the base URL is the provider's root base URL." + } + } + }, + "HydratedIntegration": { + "title": "Hydrated Integration", + "type": "object", + "required": [ + "name", + "provider" + ], + "properties": { + "name": { + "type": "string", + "example": "readSalesforceAccounts" + }, + "displayName": { + "type": "string", + "example": "Salesforce Accounts", + "x-go-type-skip-optional-pointer": true + }, + "module": { + "type": "string", + "example": "crm", + "x-go-type-skip-optional-pointer": true + }, + "provider": { + "type": "string", + "example": "salesforce" + }, + "read": { + "$ref": "#/components/schemas/HydratedIntegrationRead" + }, + "write": { + "$ref": "#/components/schemas/HydratedIntegrationWrite" + }, + "proxy": { + "$ref": "#/components/schemas/HydratedIntegrationProxy" + } + } + }, + "SelectedValueMappings": { + "title": "Selected Value Mappings", + "type": "object", + "description": "This is a map of values to their mappings. The key is the value delivered to the webhook, the value is the value coming from the provider API.", + "example": { + "open": "scheduled", + "closedWon": "won", + "closedLost": "lost" + }, + "x-go-type-skip-optional-pointer": true, + "additionalProperties": { + "type": "string" + } + }, + "DynamicMappingsInputMappedValue": { + "title": "Mapped Value", + "type": "object", + "required": [ + "mappedValue", + "mappedDisplayValue" + ], + "properties": { + "mappedValue": { + "type": "string" + }, + "mappedDisplayValue": { + "type": "string" + } + } + }, + "DynamicMappingsInputEntry": { + "title": "Field Mapping Entry", + "type": "object", + "required": [ + "mapToName" + ], + "properties": { + "mapToName": { + "type": "string", + "description": "The name of the field in your application." + }, + "mapToDisplayName": { + "type": "string", + "description": "Optional display name of the field to show the user in the mapping UI." + }, + "prompt": { + "type": "string", + "description": "Optional prompt to show the user in the mapping UI." + }, + "mappedValues": { + "type": "array", + "description": "If you would like the user to map a set of possible values, this is the list of possible values of the field in your application.", + "items": { + "$ref": "#/components/schemas/DynamicMappingsInputMappedValue" + } + }, + "fieldName": { + "type": "string", + "description": "The name of the field in SaaS provider, if present, then we will not prompt the user to map the field." + } + } + }, + "DynamicMappingsInput": { + "title": "Dynamic Mappings Input", + "description": "An array containing all available dynamic field and value mappings for this installation, provided by the InstallIntegration component. This array represents the complete set of possible mappings, regardless of which ones are currently selected. The actual selected mappings are stored separately in the selectedFieldMappings property.", + "type": "array", + "items": { + "$ref": "#/components/schemas/DynamicMappingsInputEntry" + } + }, + "SelectedFieldsAutoConfig": { + "title": "Selected Fields Auto Config", + "description": "If selectedFieldsAuto is set to all, all fields will be read.", + "type": "string", + "enum": [ + "all" + ], + "x-enum-varnames": [ + "SelectedFieldsAll" + ] + }, + "DefaultPeriodConfig": { + "title": "Default Period Config", + "type": "object", + "properties": { + "days": { + "type": "integer", + "description": "Number of days in past to backfill from. 0 is no backfill. e.g) if 10, then backfill last 10 days of data. Required if fullHistory is not set.", + "minimum": 0, + "example": 30, + "x-oapi-codegen-extra-tags": { + "validate": "required_without=FullHistory,omitempty,min=0" + } + }, + "fullHistory": { + "type": "boolean", + "description": "If true, backfill all history. Required if days is not set.", + "example": false, + "x-oapi-codegen-extra-tags": { + "validate": "required_without=Days" + } + } + } + }, + "ReadFilterValue": { + "title": "Read Filter Value", + "description": "The value to filter on. Allowed types are string, boolean, and number.", + "example": "active" + }, + "ReadFilter": { + "title": "Read Filter", + "type": "object", + "required": [ + "fieldName", + "operator" + ], + "properties": { + "fieldName": { + "type": "string", + "description": "The name of the field to filter on.", + "example": "status" + }, + "operator": { + "type": "string", + "description": "The comparison operator.", + "enum": [ + "eq" + ], + "example": "eq" + }, + "value": { + "$ref": "#/components/schemas/ReadFilterValue" + } + } + }, + "BackfillConfig": { + "title": "Backfill Config", + "type": "object", + "required": [ + "defaultPeriod" + ], + "properties": { + "defaultPeriod": { + "$ref": "#/components/schemas/DefaultPeriodConfig" + }, + "fieldFilters": { + "type": "array", + "description": "Filters to apply only during backfill. Multiple conditions are joined by AND. Use this when you want different filter behavior for backfill vs. incremental reads.\n", + "x-go-type-skip-optional-pointer": true, + "items": { + "$ref": "#/components/schemas/ReadFilter" + } + } + } + }, + "BaseReadConfigObject": { + "title": "Base Read Config Object", + "type": "object", + "properties": { + "objectName": { + "description": "The name of the object to read from.", + "example": "account", + "type": "string", + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "schedule": { + "type": "string", + "description": "The schedule for reading the object, in cron syntax.", + "example": "*/15 * * * *", + "x-go-type-skip-optional-pointer": true + }, + "disabled": { + "type": "boolean", + "description": "If this flag is set to true, scheduled reads associated with this object will be paused, and on-demand reads will not be allowed.", + "default": false + }, + "destination": { + "description": "The name of the destination that the result should be sent to.", + "example": "accountWebhook", + "type": "string", + "x-go-type-skip-optional-pointer": true + }, + "selectedFields": { + "type": "object", + "description": "This is a map of field names to booleans indicating whether they should be read. If a field is already included in `selectedFieldMappings`, it does not need to be included here.", + "example": "{ phone: true, fax: true }", + "additionalProperties": { + "type": "boolean" + } + }, + "selectedValueMappings": { + "type": "object", + "description": "This is a map of field names to their value mappings.", + "example": { + "stage": { + "open": "scheduled", + "closedWon": "won", + "closedLost": "lost" + } + }, + "x-go-type-skip-optional-pointer": true, + "additionalProperties": { + "$ref": "#/components/schemas/SelectedValueMappings" + } + }, + "dynamicMappingsInput": { + "$ref": "#/components/schemas/DynamicMappingsInput" + }, + "selectedFieldMappings": { + "type": "object", + "description": "This is a map of mapToNames to field names. (A mapTo name is the name the builder wants to map a field to when it lands in their destination.)", + "example": "{ phoneNumber: phone, faxNumber: fax }", + "additionalProperties": { + "type": "string" + } + }, + "selectedFieldsAuto": { + "$ref": "#/components/schemas/SelectedFieldsAutoConfig" + }, + "backfill": { + "$ref": "#/components/schemas/BackfillConfig" + }, + "fieldFilters": { + "type": "array", + "description": "Filters to apply when reading records during incremental reads and backfill. Multiple conditions are joined by AND. Each field can only have one condition.\n", + "x-go-type-skip-optional-pointer": true, + "items": { + "$ref": "#/components/schemas/ReadFilter" + } + } + } + }, + "BaseReadConfig": { + "title": "Base Read Config", + "type": "object", + "properties": { + "objects": { + "type": "object", + "description": "This is a map of object names to their configuration.", + "additionalProperties": { + "$ref": "#/components/schemas/BaseReadConfigObject" + } + } + } + }, + "DeletionSettings": { + "title": "Deletion Settings", + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether deletion is enabled for this object", + "example": true + } + } + }, + "ValueDefaultString": { + "title": "Value Default String", + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "string", + "description": "The value to be used as a default." + }, + "applyOnUpdate": { + "type": "string", + "enum": [ + "always", + "never" + ], + "description": "Whether the default value should be applied when updating a record.\nIf set to `always`, the default value will be applied when updating a record.\nIf set to `never`, the default value will not be applied when updating a record,\nonly when creating a record.\nIf unspecified, then `always` is assumed.\n" + } + } + }, + "ValueDefaultInteger": { + "title": "Value Default Integer", + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "integer", + "description": "The value to be used as a default." + }, + "applyOnUpdate": { + "type": "string", + "enum": [ + "always", + "never" + ], + "description": "Whether the default value should be applied when updating a record.\nIf set to `always`, the default value will be applied when updating a record.\nIf set to `never`, the default value will not be applied when updating a record,\nonly when creating a record.\nIf unspecified, then `always` is assumed.\n" + } + } + }, + "ValueDefaultBoolean": { + "title": "Value Default Boolean", + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "boolean", + "description": "The value to be used as a default." + }, + "applyOnUpdate": { + "type": "string", + "enum": [ + "always", + "never" + ], + "description": "Whether the default value should be applied when updating a record.\nIf set to `always`, the default value will be applied when updating a record.\nIf set to `never`, the default value will not be applied when updating a record,\nonly when creating a record.\nIf unspecified, then `always` is assumed.\n" + } + } + }, + "ValueDefault": { + "title": "Value Default (Legacy)", + "deprecated": true, + "x-go-type": "any", + "oneOf": [ + { + "$ref": "#/components/schemas/ValueDefaultString" + }, + { + "$ref": "#/components/schemas/ValueDefaultInteger" + }, + { + "$ref": "#/components/schemas/ValueDefaultBoolean" + } + ] + }, + "FieldSettingDefault": { + "title": "Default value for a field", + "description": "Only use one of stringValue, integerValue, booleanValue.", + "type": "object", + "properties": { + "stringValue": { + "type": "string", + "description": "The default string value to apply to a field" + }, + "integerValue": { + "type": "integer", + "description": "The default integer value to apply to a field" + }, + "booleanValue": { + "type": "boolean", + "description": "The default boolean value to apply to a field" + } + } + }, + "FieldSetting": { + "title": "Field setting", + "type": "object", + "properties": { + "default": { + "$ref": "#/components/schemas/FieldSettingDefault" + }, + "writeOnCreate": { + "type": "string", + "enum": [ + "always", + "never" + ], + "default": "always", + "x-go-type-skip-optional-pointer": true, + "description": "Whether the default value should be applied when creating a record." + }, + "writeOnUpdate": { + "type": "string", + "enum": [ + "always", + "never", + "ifEmpty" + ], + "default": "always", + "x-go-type-skip-optional-pointer": true, + "description": "Whether the default value should be applied when updating a record.\n- always: Always write to the field on update\n- never: Never write to the field on update\n- ifEmpty: Only write to the field if it's currently empty (unset or empty string). \n" + } + } + }, + "BaseWriteConfigObject": { + "title": "Base Write Config Object", + "type": "object", + "required": [ + "objectName" + ], + "properties": { + "objectName": { + "description": "The name of the object to write to.", + "example": "account", + "type": "string", + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "deletionSettings": { + "$ref": "#/components/schemas/DeletionSettings" + }, + "selectedValueDefaults": { + "type": "object", + "deprecated": true, + "description": "This is a map of field names to default values. These values will be used when writing to the object.", + "x-go-type-skip-optional-pointer": true, + "additionalProperties": { + "$ref": "#/components/schemas/ValueDefault" + } + }, + "selectedFieldSettings": { + "type": "object", + "description": "This is a map of field names to their settings.", + "x-go-type-skip-optional-pointer": true, + "additionalProperties": { + "$ref": "#/components/schemas/FieldSetting" + } + } + } + }, + "BaseWriteConfig": { + "title": "Base Write Config", + "type": "object", + "properties": { + "objects": { + "type": "object", + "description": "This is a map of object names to their configuration.", + "additionalProperties": { + "$ref": "#/components/schemas/BaseWriteConfigObject" + } + } + } + }, + "BaseProxyConfig": { + "title": "Base Proxy Config", + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "BaseConfigContent": { + "title": "Base Config Content", + "type": "object", + "properties": { + "provider": { + "description": "The SaaS API that we are integrating with.", + "example": "hubspot", + "type": "string" + }, + "read": { + "$ref": "#/components/schemas/BaseReadConfig" + }, + "write": { + "$ref": "#/components/schemas/BaseWriteConfig" + }, + "proxy": { + "$ref": "#/components/schemas/BaseProxyConfig" + } + } + }, + "ReadConfigObject": { + "title": "Read Config Object", + "allOf": [ + { + "$ref": "#/components/schemas/BaseReadConfigObject" + }, + { + "type": "object", + "required": [ + "objectName", + "selectedFields", + "selectedFieldMappings" + ] + } + ] + }, + "ReadConfig": { + "title": "Read Config", + "allOf": [ + { + "$ref": "#/components/schemas/BaseReadConfig" + }, + { + "type": "object", + "required": [ + "objects" + ], + "properties": { + "objects": { + "additionalProperties": { + "$ref": "#/components/schemas/ReadConfigObject" + } + } + } + } + ] + }, + "WriteConfigObject": { + "title": "Write Config Object", + "allOf": [ + { + "$ref": "#/components/schemas/BaseWriteConfigObject" + }, + { + "type": "object", + "required": [ + "objectName" + ] + } + ] + }, + "WriteConfig": { + "title": "Write Config", + "allOf": [ + { + "$ref": "#/components/schemas/BaseWriteConfig" + }, + { + "type": "object", + "properties": { + "objects": { + "additionalProperties": { + "$ref": "#/components/schemas/WriteConfigObject" + } + } + } + } + ] + }, + "ConfigCreateEvent": { + "title": "Create Event", + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "string", + "description": "Conditions to enable create events.", + "enum": [ + "always", + "never" + ], + "x-oapi-codegen-extra-tags": { + "validate": "oneof=always never" + } + } + } + }, + "ConfigUpdateEvent": { + "title": "Update Event", + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "string", + "description": "Conditions to enable update events.", + "example": "always", + "enum": [ + "always", + "never" + ], + "x-oapi-codegen-extra-tags": { + "validate": "oneof=always never" + } + }, + "watchFieldsAuto": { + "type": "string", + "description": "Whether to watch fields all fields automatically.", + "example": "all", + "enum": [ + "all" + ] + }, + "requiredWatchFields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The fields that should be watched.", + "example": [ + "name", + "description" + ] + } + } + }, + "ConfigDeleteEvent": { + "title": "Delete Event", + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "string", + "description": "Conditions to enable delete events.", + "example": "always", + "x-oapi-codegen-extra-tags": { + "validate": "oneof=always never" + }, + "enum": [ + "always", + "never" + ] + } + } + }, + "ConfigOtherEvents": { + "title": "Other Events", + "type": "array", + "items": { + "type": "string", + "description": "Non-standard events that the integration will subscribe to.", + "example": [ + "object.merged", + "object.restored" + ] + } + }, + "BaseSubscribeConfigObject": { + "title": "Base Subscribe Config Object", + "type": "object", + "required": [ + "objectName", + "destination", + "inheritFieldsAndMappings" + ], + "properties": { + "inheritFieldsAndMappings": { + "type": "boolean", + "description": "Whether to inherit fields and mappings from the read config.", + "example": true + }, + "objectName": { + "description": "The name of the object to subscribe to.", + "example": "account", + "type": "string", + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "destination": { + "description": "The name of the destination that the result should be sent to.", + "example": "accountWebhook", + "type": "string" + }, + "createEvent": { + "$ref": "#/components/schemas/ConfigCreateEvent" + }, + "updateEvent": { + "$ref": "#/components/schemas/ConfigUpdateEvent" + }, + "deleteEvent": { + "$ref": "#/components/schemas/ConfigDeleteEvent" + }, + "otherEvents": { + "$ref": "#/components/schemas/ConfigOtherEvents" + } + } + }, + "BaseSubscribeConfig": { + "title": "Base Subscribe Config", + "type": "object", + "properties": { + "objects": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/BaseSubscribeConfigObject" + } + } + } + }, + "SubscribeConfigObject": { + "title": "Subscribe Config Object", + "allOf": [ + { + "$ref": "#/components/schemas/BaseSubscribeConfigObject" + }, + { + "type": "object", + "required": [ + "objectName", + "destination", + "inheritFieldsAndMappings" + ] + } + ] + }, + "SubscribeConfig": { + "title": "Subscribe Config", + "allOf": [ + { + "$ref": "#/components/schemas/BaseSubscribeConfig" + }, + { + "type": "object", + "required": [ + "objects" + ], + "properties": { + "objects": { + "additionalProperties": { + "$ref": "#/components/schemas/SubscribeConfigObject" + } + } + } + } + ] + }, + "ConfigContent": { + "title": "Config Content", + "allOf": [ + { + "$ref": "#/components/schemas/BaseConfigContent" + }, + { + "type": "object", + "required": [ + "provider" + ], + "properties": { + "read": { + "$ref": "#/components/schemas/ReadConfig" + }, + "write": { + "$ref": "#/components/schemas/WriteConfig" + }, + "subscribe": { + "$ref": "#/components/schemas/SubscribeConfig" + } + } + } + ] + }, + "UpdateInstallationConfigContent": { + "title": "Update Installation Config Content", + "allOf": [ + { + "$ref": "#/components/schemas/BaseConfigContent" + }, + { + "type": "object", + "properties": { + "subscribe": { + "$ref": "#/components/schemas/BaseSubscribeConfig" + } + } + } + ] + }, + "AuthType": { + "title": "Auth Type", + "description": "The type of authentication required by the provider.", + "type": "string", + "enum": [ + "oauth2", + "apiKey", + "basic", + "jwt", + "custom", + "none" + ], + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "TokenMetadataFieldsOtherFields": { + "type": "array", + "title": "Token Metadata Fields - Other fields", + "description": "Additional fields to extract and transform from the token response", + "items": { + "type": "object", + "required": [ + "name", + "displayName", + "path" + ], + "properties": { + "name": { + "type": "string", + "description": "The internal name of the field", + "x-go-type-skip-optional-pointer": true + }, + "displayName": { + "type": "string", + "description": "The human-readable name of the field", + "x-go-type-skip-optional-pointer": true + }, + "path": { + "type": "string", + "description": "The path to the field in the token response (accepts dot notation for nested fields)", + "example": "owner.siteId", + "x-go-type-skip-optional-pointer": true + }, + "capture": { + "type": "string", + "description": "A regex expression to capture the value that we need from the path. There must be only one capture group named 'result' in the expression. If not provided, will cause an error.", + "example": "https:\\/\\/(?[^.]+)\\.docusign\\.net", + "x-go-type-skip-optional-pointer": true + } + } + } + }, + "TokenMetadataFields": { + "title": "Token Metadata Fields", + "type": "object", + "description": "Fields to be used to extract token metadata from the token response.", + "properties": { + "workspaceRefField": { + "type": "string", + "example": "account-id", + "x-go-type-skip-optional-pointer": true + }, + "consumerRefField": { + "type": "string", + "example": "user-id", + "x-go-type-skip-optional-pointer": true + }, + "scopesField": { + "type": "string", + "example": "scopes", + "x-go-type-skip-optional-pointer": true + }, + "otherFields": { + "$ref": "#/components/schemas/TokenMetadataFieldsOtherFields" + } + } + }, + "AccessTokenOptsHeader": { + "title": "Access Token Header Options", + "type": "object", + "description": "Configuration for access token in header. Must be provided if type is in-header.", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "example": "X-Access-Token", + "description": "The name of the header to be used for the access token.", + "x-go-type-skip-optional-pointer": true + }, + "valuePrefix": { + "type": "string", + "example": "Bearer ", + "description": "The prefix to be added to the access token value when it is sent in the header.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "AccessTokenOpts": { + "title": "Oauth2 Access Token Options", + "type": "object", + "description": "Configuration that defines how an OAuth 2.0 access token is attached to\noutbound API requests. When provided, this configuration overrides the\ndefault access-token handling behavior for the connector.\n", + "required": [ + "attachmentType" + ], + "properties": { + "attachmentType": { + "type": "string", + "description": "How the access token should be attached to requests.", + "enum": [ + "accessTokenHeaderAttachment" + ], + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "header": { + "$ref": "#/components/schemas/AccessTokenOptsHeader" + }, + "docsURL": { + "type": "string", + "description": "URL with more information about how access token is used.", + "example": "https://docs.example.com/oauth2-access-token-usage", + "x-go-type-skip-optional-pointer": true + } + } + }, + "Oauth2Opts": { + "title": "OAuth2 Options", + "type": "object", + "description": "Configuration for OAuth2.0. Must be provided if authType is oauth2.", + "required": [ + "grantType", + "tokenURL", + "explicitScopesRequired", + "explicitWorkspaceRequired", + "tokenMetadataFields" + ], + "properties": { + "grantType": { + "type": "string", + "enum": [ + "authorizationCode", + "authorizationCodePKCE", + "clientCredentials", + "password" + ] + }, + "authURL": { + "type": "string", + "example": "https://login.salesforce.com/services/oauth2/authorize", + "description": "The authorization URL.", + "x-go-type-skip-optional-pointer": true + }, + "tokenURL": { + "type": "string", + "example": "https://login.salesforce.com/services/oauth2/token", + "description": "The token URL.", + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "explicitScopesRequired": { + "type": "boolean", + "description": "Whether scopes are required to be known ahead of the OAuth flow.", + "example": true + }, + "explicitWorkspaceRequired": { + "type": "boolean", + "description": "Whether the workspace is required to be known ahead of the OAuth flow.", + "example": true + }, + "audience": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://api.mparticle.com" + ], + "description": "A list of URLs that represent the audience for the token, which is needed for some client credential grant flows.", + "x-go-type-skip-optional-pointer": true + }, + "scopeMappings": { + "type": "object", + "description": "Maps input scopes to their full OAuth scope values with template variable support. Scopes not in this map are passed through unchanged. Needed for some providers.", + "additionalProperties": { + "type": "string" + }, + "x-go-type-skip-optional-pointer": true, + "example": { + "default": "https://{{.workspace}}.api.com/default" + } + }, + "tokenMetadataFields": { + "$ref": "#/components/schemas/TokenMetadataFields" + }, + "docsURL": { + "type": "string", + "description": "URL with more information about where to retrieve Client ID and Client Secret, etc.", + "example": "https://docs.example.com/client-credentials", + "x-go-type-skip-optional-pointer": true + }, + "authURLParams": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-go-type-skip-optional-pointer": true, + "example": { + "access_type": "offline", + "duration": "permanent" + } + }, + "accessTokenOpts": { + "$ref": "#/components/schemas/AccessTokenOpts" + } + } + }, + "ApiKeyOptsQuery": { + "title": "API Key Query Options", + "type": "object", + "description": "Configuration for API key in query parameter. Must be provided if type is in-query.", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "example": "api_key", + "description": "The name of the query parameter to be used for the API key.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "ApiKeyOptsHeader": { + "title": "API Key Header Options", + "type": "object", + "description": "Configuration for API key in header. Must be provided if type is in-header.", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "example": "X-Api-Key", + "description": "The name of the header to be used for the API key.", + "x-go-type-skip-optional-pointer": true + }, + "valuePrefix": { + "type": "string", + "example": "Bearer ", + "description": "The prefix to be added to the API key value when it is sent in the header.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "ApiKeyOpts": { + "title": "API Key Options", + "type": "object", + "description": "Configuration for API key. Must be provided if authType is apiKey.", + "required": [ + "attachmentType" + ], + "properties": { + "attachmentType": { + "type": "string", + "description": "How the API key should be attached to requests.", + "enum": [ + "query", + "header" + ], + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "query": { + "$ref": "#/components/schemas/ApiKeyOptsQuery" + }, + "header": { + "$ref": "#/components/schemas/ApiKeyOptsHeader" + }, + "docsURL": { + "type": "string", + "description": "URL with more information about how to get or use an API key.", + "example": "https://docs.example.com/api-key", + "x-go-type-skip-optional-pointer": true + } + } + }, + "ApiKeyAsBasicOpts": { + "title": "API Key as Basic Options", + "type": "object", + "description": "when this object is present, it means that this provider uses Basic Auth to actually collect an API key", + "properties": { + "fieldUsed": { + "type": "string", + "enum": [ + "username", + "password" + ], + "example": "username", + "description": "whether the API key should be used as the username or password.", + "x-go-type-skip-optional-pointer": true, + "x-enum-varnames": [ + "UsernameField", + "PasswordField" + ] + }, + "keyFormat": { + "type": "string", + "example": "api:%s", + "description": "How to transform the API key in to a basic auth user:pass string. The %s is replaced with the API key value.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "BasicAuthOpts": { + "title": "Basic Auth Options", + "type": "object", + "description": "Configuration for Basic Auth. Optional.", + "properties": { + "apiKeyAsBasic": { + "type": "boolean", + "example": true, + "description": "If true, the provider uses an API key which then gets encoded as a basic auth user:pass string.", + "x-go-type-skip-optional-pointer": true + }, + "apiKeyAsBasicOpts": { + "$ref": "#/components/schemas/ApiKeyAsBasicOpts" + }, + "docsURL": { + "type": "string", + "description": "URL with more information about how to get or use an API key.", + "example": "https://docs.example.com/api-key", + "x-go-type-skip-optional-pointer": true + } + } + }, + "CustomAuthHeader": { + "title": "Custom Auth Header", + "type": "object", + "description": "A custom header to be used for authentication. Automatically added by the backend.", + "required": [ + "name", + "valueTemplate" + ], + "properties": { + "name": { + "type": "string", + "example": "X-Custom-Auth", + "description": "The name of the header." + }, + "valueTemplate": { + "type": "string", + "example": "Bearer {{ .token }}", + "description": "The value of the header, represented as a Golang text/template expression. Only the backend will interpret this.", + "x-oapi-codegen-extra-tags": { + "skipSubstitutions": "true" + } + } + } + }, + "CustomAuthQueryParam": { + "title": "Custom Auth Query Parameter", + "type": "object", + "description": "A custom query parameter to be used for authentication. Automatically added by the backend.", + "required": [ + "name", + "valueTemplate" + ], + "properties": { + "name": { + "type": "string", + "example": "custom_auth", + "description": "The name of the query parameter." + }, + "valueTemplate": { + "type": "string", + "example": "{{ .token }}", + "description": "The value of the query parameter, represented as a Golang text/template expression. Only the backend will interpret this.", + "x-oapi-codegen-extra-tags": { + "skipSubstitutions": "true" + } + } + } + }, + "CustomAuthInput": { + "title": "Custom Auth Input", + "type": "object", + "description": "A custom input field for authentication. This is used by the frontend to dynamically render input fields for custom auth. The backend will not interpret this. It will however receive the value of this field before making a request (in the connection secrets).", + "required": [ + "name", + "displayName" + ], + "properties": { + "name": { + "type": "string", + "example": "custom_auth_input", + "description": "The internal identifier for the custom auth input field." + }, + "displayName": { + "type": "string", + "example": "Custom Auth Input", + "description": "The human-readable name for the custom auth input field." + }, + "prompt": { + "type": "string", + "example": "See Authorization section of provider docs to obtain this value", + "description": "Some helpful text or context to be displayed to the user when asking for this input.", + "x-go-type-skip-optional-pointer": true + }, + "docsURL": { + "type": "string", + "example": "https://docs.example.com/custom-auth-input", + "description": "URL with details about this authentication mechanism and how to use it. Might be specific to this field, or a general URL for the provider. Optional.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "CustomAuthOpts": { + "title": "Custom Auth Options", + "type": "object", + "description": "Configuration for custom auth. Optional.", + "properties": { + "headers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAuthHeader" + }, + "description": "A list of custom headers to be used for authentication. The backend will add these headers.", + "x-go-type-skip-optional-pointer": true + }, + "queryParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAuthQueryParam" + }, + "description": "A list of custom query parameters to be used for authentication. The backend will add these query parameters.", + "x-go-type-skip-optional-pointer": true + }, + "inputs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAuthInput" + }, + "description": "A list of custom input fields for authentication. The frontend will render these input fields and the backend will receive the values of these fields before making a request.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "BulkWriteSupport": { + "title": "Bulk Write Support", + "type": "object", + "x-oapi-codegen-extra-tags": { + "validate": "required" + }, + "required": [ + "insert", + "update", + "upsert", + "delete" + ], + "properties": { + "insert": { + "type": "boolean" + }, + "update": { + "type": "boolean" + }, + "upsert": { + "type": "boolean" + }, + "delete": { + "type": "boolean" + } + } + }, + "SubscribeSupport": { + "title": "Subscribe Support", + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "update": { + "type": "boolean" + }, + "delete": { + "type": "boolean" + }, + "passThrough": { + "type": "boolean" + } + } + }, + "BatchWriteSupportConfig": { + "required": [ + "supported" + ], + "properties": { + "supported": { + "description": "Whether this type of batch write operation is supported", + "type": "boolean" + }, + "defaultRecordLimit": { + "description": "The default number of records supported in a batch", + "type": "integer" + }, + "objectRecordLimits": { + "description": "Defines object-level overrides for batch record limits. Keys represent object names, and values specify the maximum number of records per batch for those objects.", + "type": "object", + "additionalProperties": { + "type": "integer" + } + } + } + }, + "BatchWriteSupport": { + "required": [ + "delete", + "create", + "update", + "upsert" + ], + "properties": { + "delete": { + "$ref": "#/components/schemas/BatchWriteSupportConfig" + }, + "create": { + "$ref": "#/components/schemas/BatchWriteSupportConfig" + }, + "update": { + "$ref": "#/components/schemas/BatchWriteSupportConfig" + }, + "upsert": { + "$ref": "#/components/schemas/BatchWriteSupportConfig" + } + } + }, + "SearchOperators": { + "title": "Supported Operators for Search Action", + "type": "object", + "required": [ + "equals" + ], + "properties": { + "equals": { + "type": "boolean" + } + } + }, + "SearchSupport": { + "title": "Search Support", + "type": "object", + "required": [ + "operators" + ], + "properties": { + "operators": { + "$ref": "#/components/schemas/SearchOperators" + } + } + }, + "Support": { + "title": "Support", + "type": "object", + "description": "The supported features for the provider.", + "x-oapi-codegen-extra-tags": { + "validate": "required" + }, + "required": [ + "bulkWrite", + "proxy", + "read", + "subscribe", + "write", + "delete", + "search" + ], + "properties": { + "bulkWrite": { + "$ref": "#/components/schemas/BulkWriteSupport" + }, + "proxy": { + "type": "boolean" + }, + "read": { + "type": "boolean" + }, + "subscribe": { + "type": "boolean" + }, + "write": { + "type": "boolean" + }, + "delete": { + "type": "boolean" + }, + "subscribeSupport": { + "$ref": "#/components/schemas/SubscribeSupport" + }, + "batchWrite": { + "$ref": "#/components/schemas/BatchWriteSupport" + }, + "search": { + "$ref": "#/components/schemas/SearchSupport" + } + } + }, + "AuthHealthCheck": { + "title": "Auth Health Check", + "type": "object", + "description": "A URL to check the health of a provider's credentials. It's used to see if the credentials are valid and if the provider is reachable.", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "a no-op URL to check the health of the credentials. The URL MUST not mutate any state. If the provider doesn't have such an endpoint, then don't provide credentialsHealthCheck.", + "example": "https://api.example.com/health-check" + }, + "method": { + "type": "string", + "description": "The HTTP method to use for the health check. If not set, defaults to GET.", + "example": "GET", + "x-go-type-skip-optional-pointer": true + }, + "successStatusCodes": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "The HTTP status codes that indicate a successful health check. If not set, defaults to 200 and 204.", + "example": [ + 200, + 204 + ], + "x-go-type-skip-optional-pointer": true + } + } + }, + "MediaTypeRegular": { + "title": "Media Type Regular", + "type": "object", + "description": "Media for light/regular mode.", + "properties": { + "iconURL": { + "type": "string", + "example": "https://example.com/icon.png", + "description": "URL to the icon for the provider.", + "x-go-type-skip-optional-pointer": true + }, + "logoURL": { + "type": "string", + "example": "https://example.com/logo.png", + "description": "URL to the logo for the provider.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "MediaTypeDarkMode": { + "title": "Media Type Dark Mode", + "type": "object", + "description": "Media to be used in dark mode.", + "properties": { + "iconURL": { + "type": "string", + "example": "https://example.com/icon.png", + "description": "URL to the icon for the provider that is to be used in dark mode.", + "x-go-type-skip-optional-pointer": true + }, + "logoURL": { + "type": "string", + "example": "https://example.com/logo.png", + "description": "URL to the logo for the provider that is to be used in dark mode.", + "x-go-type-skip-optional-pointer": true + } + } + }, + "Media": { + "title": "Media", + "properties": { + "regular": { + "$ref": "#/components/schemas/MediaTypeRegular" + }, + "darkMode": { + "$ref": "#/components/schemas/MediaTypeDarkMode" + } + } + }, + "Labels": { + "title": "Labels", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "SubscribeRequirements": { + "title": "Subscribe Requirements", + "type": "object", + "description": "Declares which auxiliary steps a provider requires to support subscriptions, beyond the per-object subscribe call itself.", + "properties": { + "registration": { + "type": "boolean", + "description": "Whether the provider requires a one-time registration step that is shared across all subscribed objects. The subscribe method is object-scoped, so if a separate API call is needed beyond per-object configuration (e.g., registering a single webhook/endpoint that all object subscriptions hang off of), registration is required." + }, + "maintenance": { + "type": "boolean", + "description": "Whether the subscription requires periodic maintenance. Some providers expire subscriptions/watches after a fixed TTL, so the subscription must be renewed on a schedule to remain active." + }, + "postProcess": { + "type": "boolean", + "description": "Whether subscribing requires a third-party setup step that the connector instance itself cannot perform. Examples: Salesforce requires AWS EventBridge configuration; Gmail requires a Google Pub/Sub topic to be configured. Any configuration that must happen outside the connector falls into post-process." + }, + "subscribeByAPI": { + "type": "boolean", + "description": "Whether the provider supports programmatic subscription via API. If false, provider may still support webhooks via manual configuration in UI. " + } + } + }, + "ModuleInfo": { + "title": "Module Info", + "type": "object", + "required": [ + "displayName", + "baseURL", + "support" + ], + "properties": { + "displayName": { + "type": "string" + }, + "baseURL": { + "type": "string" + }, + "support": { + "$ref": "#/components/schemas/Support" + }, + "subscribeRequirements": { + "$ref": "#/components/schemas/SubscribeRequirements" + } + } + }, + "Modules": { + "title": "Modules that this provider supports", + "type": "object", + "description": "The registry of provider modules.", + "additionalProperties": { + "$ref": "#/components/schemas/ModuleInfo" + } + }, + "ModuleDependency": { + "title": "Module Dependency", + "type": "object", + "description": "Dependency for a single module.", + "properties": {} + }, + "ModuleDependencies": { + "title": "Module Dependencies", + "type": "object", + "description": "Specifies which modules REQUIRE (depend on) this metadata item. This field lists the modules that depend on/require the metadata item. Example: If \"workspace\" metadata has moduleDependencies: {crm: {}}, it means the CRM module requires the workspace metadata to function. Each module that needs this metadata item MUST be specified in this field. Even if it is all modules. The empty ModuleDependency {} is for future-proofing in case we need to add additional configuration options.", + "additionalProperties": { + "$ref": "#/components/schemas/ModuleDependency" + } + }, + "MetadataItemInput": { + "title": "Metadata Item (as input)", + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The internal identifier for the metadata field", + "x-go-type-skip-optional-pointer": true + }, + "displayName": { + "type": "string", + "description": "The human-readable name for the field", + "x-go-type-skip-optional-pointer": true + }, + "prompt": { + "type": "string", + "description": "Human-readable description that can contain instructions on how to collect metadata", + "x-go-type-skip-optional-pointer": true + }, + "defaultValue": { + "type": "string", + "description": "Default value for this metadata item", + "x-go-type-skip-optional-pointer": true + }, + "docsURL": { + "type": "string", + "description": "URL with more information about how to locate this value", + "example": "https://example.com/how-to-find-subdomain", + "x-go-type-skip-optional-pointer": true + }, + "moduleDependencies": { + "$ref": "#/components/schemas/ModuleDependencies", + "description": "Which modules require this metadata item (see ModuleDependencies for naming clarification)." + } + } + }, + "MetadataItemPostAuthentication": { + "title": "Metadata Item (fetched post authentication)", + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The internal identifier for the metadata field", + "x-go-type-skip-optional-pointer": true + }, + "moduleDependencies": { + "$ref": "#/components/schemas/ModuleDependencies", + "description": "Which modules require this metadata item (see ModuleDependencies for naming clarification)." + } + } + }, + "ProviderMetadata-2": { + "title": "Provider Metadata", + "type": "object", + "description": "Provider metadata that needs to be given by the user or fetched by the connector post authentication for the connector to work.", + "properties": { + "input": { + "type": "array", + "description": "Metadata provided as manual input", + "items": { + "$ref": "#/components/schemas/MetadataItemInput" + }, + "x-go-type-skip-optional-pointer": true + }, + "postAuthentication": { + "type": "array", + "description": "Metadata fetched by the connector post authentication", + "items": { + "$ref": "#/components/schemas/MetadataItemPostAuthentication" + }, + "x-go-type-skip-optional-pointer": true + } + } + }, + "ProviderAppMetadata-2": { + "title": "Provider App Metadata", + "type": "object", + "description": "Describes the provider-app-level fields that the Ampersand dashboard should collect from the builder when creating a ProviderApp for this provider. These descriptors tell the dashboard which form fields to render; the submitted values are stored in ProviderApp.metadata.", + "properties": { + "authQueryParams": { + "type": "array", + "description": "Descriptors for fields stored in ProviderApp.metadata.authQueryParams (e.g., optional_scope for HubSpot).", + "items": { + "$ref": "#/components/schemas/MetadataItemInput" + }, + "x-go-type-skip-optional-pointer": true + }, + "providerParams": { + "type": "array", + "description": "Descriptors for fields stored in ProviderApp.metadata.providerParams (e.g., packageInstallURL for Salesforce, gcpProjectId for Gmail).", + "items": { + "$ref": "#/components/schemas/MetadataItemInput" + }, + "x-go-type-skip-optional-pointer": true + } + } + }, + "ProviderInfo": { + "title": "Provider Info", + "type": "object", + "required": [ + "name", + "baseURL", + "authType", + "support", + "defaultModule" + ], + "properties": { + "name": { + "type": "string" + }, + "authType": { + "$ref": "#/components/schemas/AuthType" + }, + "baseURL": { + "description": "The base URL for making API requests.", + "type": "string", + "x-oapi-codegen-extra-tags": { + "validate": "required" + } + }, + "defaultModule": { + "type": "string" + }, + "oauth2Opts": { + "$ref": "#/components/schemas/Oauth2Opts" + }, + "apiKeyOpts": { + "$ref": "#/components/schemas/ApiKeyOpts" + }, + "basicOpts": { + "$ref": "#/components/schemas/BasicAuthOpts" + }, + "customOpts": { + "$ref": "#/components/schemas/CustomAuthOpts" + }, + "support": { + "$ref": "#/components/schemas/Support" + }, + "authHealthCheck": { + "$ref": "#/components/schemas/AuthHealthCheck" + }, + "displayName": { + "type": "string", + "example": "Zendesk Chat", + "description": "The display name of the provider, if omitted, defaults to provider name.", + "x-go-type-skip-optional-pointer": true + }, + "postAuthInfoNeeded": { + "type": "boolean", + "example": true, + "description": "If true, we require additional information after auth to start making requests.", + "x-go-type-skip-optional-pointer": true + }, + "media": { + "$ref": "#/components/schemas/Media" + }, + "labels": { + "$ref": "#/components/schemas/Labels" + }, + "subscribeRequirements": { + "$ref": "#/components/schemas/SubscribeRequirements" + }, + "modules": { + "$ref": "#/components/schemas/Modules" + }, + "metadata": { + "$ref": "#/components/schemas/ProviderMetadata-2" + }, + "providerAppMetadata": { + "$ref": "#/components/schemas/ProviderAppMetadata-2" + } + } + }, + "CatalogType": { + "title": "Catalog Type", + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ProviderInfo" + } + } + }, + "securitySchemes": { + "APIKeyHeader": { + "type": "apiKey", + "name": "X-Api-Key", + "in": "header" + }, + "Bearer": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + }, + "security": [ + { + "APIKeyHeader": [] + }, + { + "Bearer": [] + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 1923fb4..5fe6066 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "@apidevtools/swagger-parser": "^10.1.0" }, "devDependencies": { + "@redocly/openapi-core": "^2.36.0", "@types/node": "^20.14.10", "husky": "^9.0.11", "typescript": "^5.4.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b250700..63344a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,9 @@ importers: specifier: ^10.1.0 version: 10.1.0(openapi-types@12.1.3) devDependencies: + '@redocly/openapi-core': + specifier: ^2.36.0 + version: 2.36.0 '@types/node': specifier: ^20.14.10 version: 20.14.10 @@ -46,9 +49,26 @@ packages: peerDependencies: openapi-types: '>=7' + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@redocly/ajv@8.18.1': + resolution: {integrity: sha512-Ifm/pP/tul1qmAecpbVxCBluVE32rKfjf8gYXH4xI2gCv9mRWFhJMHzkPDM4TXlxwPQYIFegymlsy8lXz7optA==} + + '@redocly/ajv@8.18.3': + resolution: {integrity: sha512-l42u0of3hY98sN2A+M4qTX1O/KrpgGH32Hu9kP2GtHyD5Dfqq86PKFLe5dwaD8DEnNmlOlll2BAmeEtf0DaySg==} + + '@redocly/config@0.49.1': + resolution: {integrity: sha512-Eid8/bDcsf2bpTJ2qZhULflf6Y/TtoUFZt0+a5XZzjZj0uA8L8EQiY/nEdBd6lZQlZsnu8/cAUhTyBebnLi0gA==} + + '@redocly/openapi-core@2.36.0': + resolution: {integrity: sha512-u44e3yn0Zj2d59+SzMrHVj0DQZfQJm8C8uaf4MhJDAiHLHyd7adcAoRiqDD+LzkfLvgBepp20Jo6gDEIGl1mDg==} + engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -63,6 +83,14 @@ packages: ajv: optional: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} @@ -75,6 +103,9 @@ packages: call-me-maybe@1.0.2: resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -91,6 +122,10 @@ packages: engines: {node: '>=18'} hasBin: true + js-levenshtein@1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -99,12 +134,28 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} + hasBin: true + + json-schema-to-ts@2.7.2: + resolution: {integrity: sha512-R1JfqKqbBR4qE8UyBR56Ms30LL62/nlhoz+1UkfI/VE7p54Awu919FZ6ZUPG8zIa3XB65usPJgr1ONVncUGSaQ==} + engines: {node: '>=16'} + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} openapi-types@12.1.3: resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -112,6 +163,9 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + ts-algebra@1.2.2: + resolution: {integrity: sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==} + typescript@5.5.3: resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} engines: {node: '>=14.17'} @@ -120,6 +174,9 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + snapshots: '@apidevtools/json-schema-ref-parser@11.6.4': @@ -149,8 +206,41 @@ snapshots: call-me-maybe: 1.0.2 openapi-types: 12.1.3 + '@babel/runtime@7.29.7': {} + '@jsdevtools/ono@7.1.3': {} + '@redocly/ajv@8.18.1': + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.1 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + '@redocly/ajv@8.18.3': + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.1 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + '@redocly/config@0.49.1': + dependencies: + json-schema-to-ts: 2.7.2 + + '@redocly/openapi-core@2.36.0': + dependencies: + '@redocly/ajv': 8.18.3 + '@redocly/config': 0.49.1 + ajv: '@redocly/ajv@8.18.1' + ajv-formats: 3.0.1(@redocly/ajv@8.18.1) + colorette: 1.4.0 + js-levenshtein: 1.1.6 + js-yaml: 4.3.0 + picomatch: 4.0.5 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + '@types/json-schema@7.0.15': {} '@types/node@20.14.10': @@ -158,9 +248,13 @@ snapshots: undici-types: 5.26.5 ajv-draft-04@1.0.0(ajv@8.17.1): - dependencies: + optionalDependencies: ajv: 8.17.1 + ajv-formats@3.0.1(@redocly/ajv@8.18.1): + optionalDependencies: + ajv: '@redocly/ajv@8.18.1' + ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 @@ -176,6 +270,8 @@ snapshots: call-me-maybe@1.0.2: {} + colorette@1.4.0: {} + esprima@4.0.1: {} fast-deep-equal@3.1.3: {} @@ -184,6 +280,8 @@ snapshots: husky@9.0.11: {} + js-levenshtein@1.1.6: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -193,14 +291,32 @@ snapshots: dependencies: argparse: 2.0.1 + js-yaml@4.3.0: + dependencies: + argparse: 2.0.1 + + json-schema-to-ts@2.7.2: + dependencies: + '@babel/runtime': 7.29.7 + '@types/json-schema': 7.0.15 + ts-algebra: 1.2.2 + json-schema-traverse@1.0.0: {} openapi-types@12.1.3: {} + picomatch@4.0.5: {} + + pluralize@8.0.0: {} + require-from-string@2.0.2: {} sprintf-js@1.0.3: {} + ts-algebra@1.2.2: {} + typescript@5.5.3: {} undici-types@5.26.5: {} + + yaml-ast-parser@0.0.43: {} diff --git a/scripts/generate-json.ts b/scripts/generate-json.ts index c76c5b7..a1ad1f0 100644 --- a/scripts/generate-json.ts +++ b/scripts/generate-json.ts @@ -6,6 +6,7 @@ */ import SwaggerParser from "@apidevtools/swagger-parser"; +import { bundle, createConfig } from "@redocly/openapi-core"; import fs from "fs"; import path from "path"; @@ -72,4 +73,51 @@ async function deRefOpenApiSpecs() { } } -deRefOpenApiSpecs(); +/** + * Bundled (as opposed to dereferenced) specs. Bundling merges external-file + * $refs into a single document's components while preserving *internal* $refs + * (e.g. Installation.connection stays `$ref: '#/components/schemas/Connection'`). + * + * The dereferenced api.json above inlines every $ref, which makes code + * generators (e.g. oapi-codegen consumed by amp-common) emit anonymous nested + * structs instead of reusing named component types. The bundled artifact keeps + * those references so generated code gets shared, named types. It does not + * replace the dereferenced JSON, which downstream docs generation relies on. + * + * We use Redocly (rather than swagger-parser's bundle) because it hoists every + * shared schema into components/schemas with clean `#/components/schemas/...` + * refs. swagger-parser's bundle instead points duplicate refs into the first + * occurrence's `properties`, which oapi-codegen's loader cannot consume. + */ +const bundledSpecs = [ + { + inputFile: path.join(__dirname, "../api/api.yaml"), + outputFile: path.join(__dirname, "../api/generated/api.bundled.json"), + }, +]; + +async function bundleOpenApiSpecs() { + try { + const config = await createConfig({}); + + await Promise.all(bundledSpecs.map(async (spec) => { + const result = await bundle({ + ref: spec.inputFile, + config, + dereference: false, + }); + const bundledSpec = JSON.stringify(result.bundle.parsed, null, 2); + fs.writeFileSync(spec.outputFile, bundledSpec); + console.log(`Bundled OpenAPI spec saved to ${spec.outputFile}`); + })); + } catch (error) { + console.error(`Error bundling OpenAPI spec: ${error.message}`); + } +} + +async function main() { + await deRefOpenApiSpecs(); + await bundleOpenApiSpecs(); +} + +main();