i18n - docs translations (#18534)
Created by Github action --------- Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
d1c95e380e
commit
982f0c4a4d
+1
-1
@@ -77,7 +77,7 @@ To avoid unnecessary [re-renders](/l/pt/developers/contribute/capabilities/front
|
||||
|
||||
### Gerenciamento de Estado
|
||||
|
||||
[Jotai](https://jotai.org/) gerencia o estado.
|
||||
[Jotai](https://jotai.org/) handles state management.
|
||||
|
||||
Veja [melhores práticas](/l/pt/developers/contribute/capabilities/frontend-development/best-practices-front#state-management) para mais informações sobre gerenciamento de estado.
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: APIs
|
||||
description: Consulte e modifique seus dados de CRM programaticamente usando REST ou GraphQL.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
O Twenty foi desenvolvido para ser amigável ao desenvolvedor, oferecendo APIs poderosas que se adaptam ao seu modelo de dados personalizado. Oferecemos quatro tipos distintos de API para atender diferentes necessidades de integração.
|
||||
|
||||
## Abordagem Focada no Desenvolvedor
|
||||
|
||||
Twenty gera APIs especificamente para o seu modelo de dados:
|
||||
|
||||
* **Nenhum ID longo necessário**: Use os nomes dos seus objetos e campos diretamente nos endpoints
|
||||
* **Objetos padrão e personalizados tratados igualmente**: Seus objetos personalizados recebem o mesmo tratamento de API que os incorporados
|
||||
* **Endpoints dedicados**: Cada objeto e campo tem seu próprio endpoint de API
|
||||
* **Documentação personalizada**: Gerada especificamente para o modelo de dados do seu workspace
|
||||
|
||||
<Note>
|
||||
Sua documentação de API personalizada fica disponível em **Configurações → API & Webhooks** após criar uma chave de API. Como o Twenty gera APIs que correspondem ao seu modelo de dados personalizado, a documentação é exclusiva do seu workspace.
|
||||
</Note>
|
||||
|
||||
## Os dois tipos de API
|
||||
|
||||
### Core API
|
||||
|
||||
Acessada em `/rest/` ou `/graphql/`
|
||||
|
||||
Trabalhe com seus **registros** (os dados):
|
||||
|
||||
* Criar, ler, atualizar e excluir Pessoas, Empresas, Oportunidades, etc.
|
||||
* Consultar e filtrar dados
|
||||
* Gerenciar relações de registros
|
||||
|
||||
### Metadata API
|
||||
|
||||
Acessada em `/rest/metadata/` ou `/metadata/`
|
||||
|
||||
Gerencie seu **workspace e modelo de dados**:
|
||||
|
||||
* Criar, modificar ou excluir objetos e campos
|
||||
* Configurar as configurações do workspace
|
||||
* Defina relacionamentos entre objetos
|
||||
|
||||
## REST vs GraphQL
|
||||
|
||||
As APIs Core e Metadata estão disponíveis nos formatos REST e GraphQL:
|
||||
|
||||
| Formato | Operações disponíveis |
|
||||
| ----------- | --------------------------------------------------------------------------------- |
|
||||
| **REST** | CRUD, operações em lote, upserts |
|
||||
| **GraphQL** | Os mesmos + **upserts em lote**, consultas de relacionamento em uma única chamada |
|
||||
|
||||
Escolha com base nas suas necessidades — ambos os formatos acessam os mesmos dados.
|
||||
|
||||
## Endpoints de API
|
||||
|
||||
| Ambiente | URL base |
|
||||
| ------------------ | ------------------------- |
|
||||
| **Nuvem** | `https://api.twenty.com/` |
|
||||
| **Auto-hospedado** | `https://{your-domain}/` |
|
||||
|
||||
## Autenticação
|
||||
|
||||
Toda solicitação de API requer uma chave de API no cabeçalho:
|
||||
|
||||
```
|
||||
Authorization: Bearer YOUR_API_KEY
|
||||
```
|
||||
|
||||
### Criar uma Chave de API
|
||||
|
||||
1. Vá para **Configurações → APIs & Webhooks**
|
||||
2. Clique em **+ Criar chave**
|
||||
3. Configurar:
|
||||
* **Nome**: Nome descritivo para a chave
|
||||
* **Data de expiração**: Quando a chave expira
|
||||
4. Clique em **Salvar**
|
||||
5. **Copie imediatamente** — a chave é exibida apenas uma vez
|
||||
|
||||
<VimeoEmbed videoId="928786722" title="Criando chave de API" />
|
||||
|
||||
<Warning>
|
||||
Sua chave de API concede acesso a dados confidenciais. Não a compartilhe com serviços não confiáveis. Se for comprometida, desative-a imediatamente e gere uma nova.
|
||||
</Warning>
|
||||
|
||||
### Atribuir uma função a uma chave de API
|
||||
|
||||
Para maior segurança, atribua uma função específica para limitar o acesso:
|
||||
|
||||
1. Vá para **Configurações → Funções**
|
||||
2. Clique na função que deseja atribuir
|
||||
3. Abra a aba de **Atribuição**
|
||||
4. Em **Chaves de API**, clique em **+ Atribuir à chave de API**
|
||||
5. Selecione a chave de API
|
||||
|
||||
A chave herdará as permissões dessa função. Veja [Permissões](/l/pt/user-guide/permissions-access/capabilities/permissions) para obter detalhes.
|
||||
|
||||
### Gerenciar Chaves de API
|
||||
|
||||
**Regenerar**: Configurações → APIs & Webhooks → Clique na chave → **Regenerar**
|
||||
|
||||
**Excluir**: Configurações → APIs & Webhooks → Clique na chave → **Excluir**
|
||||
|
||||
## Playground de API
|
||||
|
||||
Teste suas APIs diretamente no navegador com nosso playground integrado — disponível tanto para **REST** quanto para **GraphQL**.
|
||||
|
||||
### Acesse o Playground
|
||||
|
||||
1. Vá para **Configurações → APIs & Webhooks**
|
||||
2. Crie uma chave de API (obrigatório)
|
||||
3. Clique em **REST API** ou **GraphQL API** para abrir o playground
|
||||
|
||||
### O que você obtém
|
||||
|
||||
* **Documentação interativa**: Gerada para o seu modelo de dados específico
|
||||
* **Testes ao vivo**: Execute chamadas de API reais no seu workspace
|
||||
* **Explorador de esquema**: Navegue pelos objetos, campos e relacionamentos disponíveis
|
||||
* **Construtor de solicitações**: Construa consultas com preenchimento automático
|
||||
|
||||
O playground reflete seus objetos e campos personalizados, portanto, a documentação está sempre precisa para o seu workspace.
|
||||
|
||||
## Operações em Lote
|
||||
|
||||
Tanto REST quanto GraphQL suportam operações em lote:
|
||||
|
||||
* **Tamanho do lote**: Até 60 registros por requisição
|
||||
* **Operações**: Criar, atualizar e excluir vários registros
|
||||
|
||||
**Recursos exclusivos do GraphQL:**
|
||||
|
||||
* **Upsert em lote**: Criar ou atualizar em uma única chamada
|
||||
* Use nomes de objetos no plural (por exemplo, `CreateCompanies` em vez de `CreateCompany`)
|
||||
|
||||
## Limites de taxa
|
||||
|
||||
As solicitações de API são limitadas para garantir a estabilidade da plataforma:
|
||||
|
||||
| Limite | Valor |
|
||||
| ------------------- | ------------------------ |
|
||||
| **Solicitações** | 100 chamadas por minuto |
|
||||
| **Tamanho do lote** | 60 registros por chamada |
|
||||
|
||||
<Tip>
|
||||
Use operações em lote para maximizar a taxa de transferência — processe até 60 registros em uma única chamada de API em vez de fazer solicitações individuais.
|
||||
</Tip>
|
||||
@@ -0,0 +1,689 @@
|
||||
---
|
||||
title: Criando aplicativos
|
||||
description: Defina objetos, funções de lógica, componentes de front-end e muito mais com o SDK da Twenty.
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Os aplicativos estão atualmente em testes alfa. O recurso é funcional, mas ainda está evoluindo.
|
||||
</Warning>
|
||||
|
||||
## Use os recursos do SDK (tipos e configuração)
|
||||
|
||||
O twenty-sdk fornece blocos de construção tipados e funções utilitárias que você usa dentro do seu aplicativo. A seguir estão as partes principais que você usará com mais frequência.
|
||||
|
||||
### Funções utilitárias
|
||||
|
||||
O SDK fornece funções utilitárias para definir as entidades do seu app. Conforme descrito em [Detecção de entidades](/l/pt/developers/extend/apps/getting-started#entity-detection), você deve usar `export default define<Entity>({...})` para que suas entidades sejam detectadas:
|
||||
|
||||
| Função | Finalidade |
|
||||
| -------------------------------- | ------------------------------------------------------------------ |
|
||||
| `defineApplication` | Configurar metadados do aplicativo (obrigatório, um por app) |
|
||||
| `defineObject` | Define objetos personalizados com campos |
|
||||
| `defineLogicFunction` | Defina funções de lógica com handlers |
|
||||
| `definePreInstallLogicFunction` | Defina uma função de lógica de pré-instalação (uma por aplicativo) |
|
||||
| `definePostInstallLogicFunction` | Defina uma função de lógica de pós-instalação (uma por aplicativo) |
|
||||
| `defineFrontComponent` | Definir componentes de front-end para UI personalizada |
|
||||
| `defineRole` | Configura permissões de papéis e acesso a objetos |
|
||||
| `defineField` | Estender objetos existentes com campos adicionais |
|
||||
| `defineView` | Define visualizações salvas para objetos |
|
||||
| `defineNavigationMenuItem` | Define links de navegação da barra lateral |
|
||||
| `defineSkill` | Define habilidades de agente de IA |
|
||||
|
||||
Essas funções validam sua configuração em tempo de compilação e oferecem autocompletar na IDE e segurança de tipos.
|
||||
|
||||
### Definindo objetos
|
||||
|
||||
Objetos personalizados descrevem tanto o esquema quanto o comportamento de registros no seu espaço de trabalho. Use `defineObject()` para definir objetos com validação integrada:
|
||||
|
||||
```typescript
|
||||
// src/app/postCard.object.ts
|
||||
import { defineObject, FieldType } from 'twenty-sdk';
|
||||
|
||||
enum PostCardStatus {
|
||||
DRAFT = 'DRAFT',
|
||||
SENT = 'SENT',
|
||||
DELIVERED = 'DELIVERED',
|
||||
RETURNED = 'RETURNED',
|
||||
}
|
||||
|
||||
export default defineObject({
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
nameSingular: 'postCard',
|
||||
namePlural: 'postCards',
|
||||
labelSingular: 'Post Card',
|
||||
labelPlural: 'Post Cards',
|
||||
description: 'A post card object',
|
||||
icon: 'IconMail',
|
||||
fields: [
|
||||
{
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
name: 'content',
|
||||
type: FieldType.TEXT,
|
||||
label: 'Content',
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
},
|
||||
{
|
||||
universalIdentifier: 'c6aa31f3-da76-4ac6-889f-475e226009ac',
|
||||
name: 'recipientName',
|
||||
type: FieldType.FULL_NAME,
|
||||
label: 'Recipient name',
|
||||
icon: 'IconUser',
|
||||
},
|
||||
{
|
||||
universalIdentifier: '95045777-a0ad-49ec-98f9-22f9fc0c8266',
|
||||
name: 'recipientAddress',
|
||||
type: FieldType.ADDRESS,
|
||||
label: 'Recipient address',
|
||||
icon: 'IconHome',
|
||||
},
|
||||
{
|
||||
universalIdentifier: '87b675b8-dd8c-4448-b4ca-20e5a2234a1e',
|
||||
name: 'status',
|
||||
type: FieldType.SELECT,
|
||||
label: 'Status',
|
||||
icon: 'IconSend',
|
||||
defaultValue: `'${PostCardStatus.DRAFT}'`,
|
||||
options: [
|
||||
{ value: PostCardStatus.DRAFT, label: 'Draft', position: 0, color: 'gray' },
|
||||
{ value: PostCardStatus.SENT, label: 'Sent', position: 1, color: 'orange' },
|
||||
{ value: PostCardStatus.DELIVERED, label: 'Delivered', position: 2, color: 'green' },
|
||||
{ value: PostCardStatus.RETURNED, label: 'Returned', position: 3, color: 'orange' },
|
||||
],
|
||||
},
|
||||
{
|
||||
universalIdentifier: 'e06abe72-5b44-4e7f-93be-afc185a3c433',
|
||||
name: 'deliveredAt',
|
||||
type: FieldType.DATE_TIME,
|
||||
label: 'Delivered at',
|
||||
icon: 'IconCheck',
|
||||
isNullable: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* Use `defineObject()` para validação integrada e melhor suporte na IDE.
|
||||
* O `universalIdentifier` deve ser exclusivo e estável entre implantações.
|
||||
* Cada campo requer `name`, `type`, `label` e seu próprio `universalIdentifier` estável.
|
||||
* O array `fields` é opcional — você pode definir objetos sem campos personalizados.
|
||||
* Você pode criar novos objetos usando `yarn twenty entity:add`, que orienta você sobre nomeação, campos e relacionamentos.
|
||||
|
||||
<Note>
|
||||
**Os campos base são criados automaticamente.** Quando você define um objeto personalizado, o Twenty adiciona automaticamente campos padrão
|
||||
como `id`, `name`, `createdAt`, `updatedAt`, `createdBy`, `updatedBy` e `deletedAt`.
|
||||
Você não precisa definir esses no seu array `fields` — adicione apenas seus campos personalizados.
|
||||
Você pode substituir os campos padrão definindo um campo com o mesmo nome no seu array `fields`,
|
||||
mas isso não é recomendado.
|
||||
</Note>
|
||||
|
||||
### Configuração do aplicativo (application-config.ts)
|
||||
|
||||
Todo aplicativo tem um único arquivo `application-config.ts` que descreve:
|
||||
|
||||
* **O que é o aplicativo**: identificadores, nome de exibição e descrição.
|
||||
* **Como suas funções são executadas**: qual papel usam para permissões.
|
||||
* **Variáveis (opcional)**: pares chave–valor expostos às suas funções como variáveis de ambiente.
|
||||
* **(Opcional) função de pré-instalação**: uma função de lógica que é executada antes da instalação do aplicativo.
|
||||
* **(Opcional) função de pós-instalação**: uma função de lógica que é executada após a instalação do aplicativo.
|
||||
|
||||
Use `defineApplication()` para definir a configuração do seu aplicativo:
|
||||
|
||||
```typescript
|
||||
// src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
applicationVariables: {
|
||||
DEFAULT_RECIPIENT_NAME: {
|
||||
universalIdentifier: '19e94e59-d4fe-4251-8981-b96d0a9f74de',
|
||||
description: 'Default recipient name for postcards',
|
||||
value: 'Jane Doe',
|
||||
isSecret: false,
|
||||
},
|
||||
},
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
```
|
||||
|
||||
Notas:
|
||||
|
||||
* `universalIdentifier` são IDs determinísticos que você controla; gere-os uma vez e mantenha-os estáveis entre sincronizações.
|
||||
* `applicationVariables` tornam-se variáveis de ambiente para suas funções (por exemplo, `DEFAULT_RECIPIENT_NAME` fica disponível como `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` deve corresponder ao arquivo do papel (veja abaixo).
|
||||
* As funções de pré-instalação e pós-instalação são detectadas automaticamente durante a geração do manifesto. Consulte [Funções de pré-instalação](#pre-install-functions) e [Funções de pós-instalação](#post-install-functions).
|
||||
|
||||
#### Papéis e permissões
|
||||
|
||||
Os aplicativos podem definir papéis que encapsulam permissões sobre os objetos e ações do seu espaço de trabalho. O campo `defaultRoleUniversalIdentifier` em `application-config.ts` designa o papel padrão usado pelas funções de lógica do seu app.
|
||||
|
||||
* A chave de API em tempo de execução, injetada como `TWENTY_API_KEY`, é derivada desse papel padrão de função.
|
||||
* O cliente tipado ficará restrito às permissões concedidas a esse papel.
|
||||
* Siga o princípio do menor privilégio: crie um papel dedicado com apenas as permissões de que suas funções precisam e, em seguida, faça referência ao seu identificador universal.
|
||||
|
||||
##### Papel de função padrão (*.role.ts)
|
||||
|
||||
Ao criar um novo aplicativo com o scaffold, a CLI também cria um arquivo de papel padrão. Use `defineRole()` para definir papéis com validação integrada:
|
||||
|
||||
```typescript
|
||||
// src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'b648f87b-1d26-4961-b974-0908fd991061';
|
||||
|
||||
export default defineRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Default function role',
|
||||
description: 'Default role for function Twenty client',
|
||||
canReadAllObjectRecords: false,
|
||||
canUpdateAllObjectRecords: false,
|
||||
canSoftDeleteAllObjectRecords: false,
|
||||
canDestroyAllObjectRecords: false,
|
||||
canUpdateAllSettings: false,
|
||||
canBeAssignedToAgents: false,
|
||||
canBeAssignedToUsers: false,
|
||||
canBeAssignedToApiKeys: false,
|
||||
objectPermissions: [
|
||||
{
|
||||
objectUniversalIdentifier: '9f9882af-170c-4879-b013-f9628b77c050',
|
||||
canReadObjectRecords: true,
|
||||
canUpdateObjectRecords: true,
|
||||
canSoftDeleteObjectRecords: false,
|
||||
canDestroyObjectRecords: false,
|
||||
},
|
||||
],
|
||||
fieldPermissions: [
|
||||
{
|
||||
objectUniversalIdentifier: '9f9882af-170c-4879-b013-f9628b77c050',
|
||||
fieldUniversalIdentifier: 'b2c37dc0-8ae7-470e-96cd-1476b47dfaff',
|
||||
canReadFieldValue: false,
|
||||
canUpdateFieldValue: false,
|
||||
},
|
||||
],
|
||||
permissionFlags: [PermissionFlag.APPLICATIONS],
|
||||
});
|
||||
```
|
||||
|
||||
O `universalIdentifier` desse papel é então referenciado em `application-config.ts` como `defaultRoleUniversalIdentifier`. Em outras palavras:
|
||||
|
||||
* **\*.role.ts** define o que o papel de função padrão pode fazer.
|
||||
* **application-config.ts** aponta para esse papel para que suas funções herdem suas permissões.
|
||||
|
||||
Notas:
|
||||
|
||||
* Comece pelo papel gerado pelo scaffold e depois restrinja-o progressivamente seguindo o princípio do menor privilégio.
|
||||
* Substitua `objectPermissions` e `fieldPermissions` pelos objetos/campos de que suas funções precisam.
|
||||
* `permissionFlags` controlam o acesso a recursos em nível de plataforma. Mantenha-os mínimos; adicione apenas o que for necessário.
|
||||
* Veja um exemplo funcional no app Hello World: [`packages/twenty-apps/hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
|
||||
### Configuração de função de lógica e ponto de entrada
|
||||
|
||||
Cada arquivo de função usa `defineLogicFunction()` para exportar uma configuração com um handler e gatilhos opcionais.
|
||||
|
||||
```typescript
|
||||
// src/app/createPostCard.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk';
|
||||
import { CoreApiClient, type Person } from 'twenty-sdk/generated';
|
||||
|
||||
const handler = async (params: RoutePayload) => {
|
||||
const client = new CoreApiClient();
|
||||
const name = 'name' in params.queryStringParameters
|
||||
? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
: 'Hello world';
|
||||
|
||||
const result = await client.mutation({
|
||||
createPostCard: {
|
||||
__args: { data: { name } },
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
|
||||
name: 'create-new-post-card',
|
||||
timeoutSeconds: 2,
|
||||
handler,
|
||||
triggers: [
|
||||
// Public HTTP route trigger '/s/post-card/create'
|
||||
{
|
||||
universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6',
|
||||
type: 'route',
|
||||
path: '/post-card/create',
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: false,
|
||||
},
|
||||
// Cron trigger (CRON pattern)
|
||||
// {
|
||||
// universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
// type: 'cron',
|
||||
// pattern: '0 0 1 1 *',
|
||||
// },
|
||||
// Database event trigger
|
||||
// {
|
||||
// universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
// type: 'databaseEvent',
|
||||
// eventName: 'person.updated',
|
||||
// updatedFields: ['name'],
|
||||
// },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
Tipos de gatilho comuns:
|
||||
|
||||
* **route**: Expõe sua função em um caminho e método HTTP **no endpoint `/s/`**:
|
||||
|
||||
> por exemplo, `path: '/post-card/create',` -> chamar em `<APP_URL>/s/post-card/create`
|
||||
|
||||
* **cron**: Executa sua função em um agendamento usando uma expressão CRON.
|
||||
* **databaseEvent**: Executa em eventos do ciclo de vida de objetos do espaço de trabalho. Quando a operação do evento é `updated`, campos específicos a serem observados podem ser especificados no array `updatedFields`. Se deixar indefinido ou vazio, qualquer atualização acionará a função.
|
||||
|
||||
> por exemplo, `person.updated`
|
||||
|
||||
Notas:
|
||||
|
||||
* O array `triggers` é opcional. Funções sem gatilhos podem ser usadas como funções utilitárias chamadas por outras funções.
|
||||
* Você pode misturar vários tipos de gatilho em uma única função.
|
||||
|
||||
### Funções de pré-instalação
|
||||
|
||||
Uma função de pré-instalação é uma função de lógica que é executada automaticamente antes de o seu aplicativo ser instalado em um espaço de trabalho. Isso é útil para tarefas de validação, verificações de pré-requisitos ou para preparar o estado do espaço de trabalho antes que a instalação principal prossiga.
|
||||
|
||||
Ao criar a estrutura de um novo app com `create-twenty-app`, uma função de pré-instalação é gerada para você em `src/logic-functions/pre-install.ts`:
|
||||
|
||||
```typescript
|
||||
// src/logic-functions/pre-install.ts
|
||||
import { definePreInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk';
|
||||
|
||||
const handler = async (payload: InstallLogicFunctionPayload): Promise<void> => {
|
||||
console.log('Pre install logic function executed successfully!', payload.previousVersion);
|
||||
};
|
||||
|
||||
export default definePreInstallLogicFunction({
|
||||
universalIdentifier: '<generated-uuid>',
|
||||
name: 'pre-install',
|
||||
description: 'Runs before installation to prepare the application.',
|
||||
timeoutSeconds: 300,
|
||||
handler,
|
||||
});
|
||||
```
|
||||
|
||||
Você também pode executar manualmente a função de pré-instalação a qualquer momento usando a CLI:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty function:execute --preInstall
|
||||
```
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* As funções de pré-instalação usam `definePreInstallLogicFunction()` — uma variante especializada que omite as configurações de gatilho (`cronTriggerSettings`, `databaseEventTriggerSettings`, `httpRouteTriggerSettings`, `isTool`).
|
||||
* O manipulador recebe um `InstallLogicFunctionPayload` com `{ previousVersion: string }` — a versão do app que foi instalada anteriormente (ou uma string vazia para instalações novas).
|
||||
* É permitida apenas uma função de pré-instalação por app. A geração do manifesto apresentará erro se mais de uma for detectada.
|
||||
* O `universalIdentifier` da função é definido automaticamente como `preInstallLogicFunctionUniversalIdentifier` no manifesto do aplicativo durante a geração — você não precisa referenciá-lo em `defineApplication()`.
|
||||
* O tempo limite padrão é definido como 300 segundos (5 minutos) para permitir tarefas de preparação mais longas.
|
||||
* As funções de pré-instalação não precisam de gatilhos — elas são invocadas pela plataforma antes da instalação ou manualmente via `function:execute --preInstall`.
|
||||
|
||||
### Funções de pós-instalação
|
||||
|
||||
Uma função de pós-instalação é uma função de lógica que é executada automaticamente após o seu aplicativo ser instalado em um espaço de trabalho. Isso é útil para tarefas de configuração únicas, como preencher dados padrão, criar registros iniciais ou configurar as configurações do espaço de trabalho.
|
||||
|
||||
Ao criar a estrutura de um novo app com `create-twenty-app`, uma função de pós-instalação é gerada para você em `src/logic-functions/post-install.ts`:
|
||||
|
||||
```typescript
|
||||
// src/logic-functions/post-install.ts
|
||||
import { definePostInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk';
|
||||
|
||||
const handler = async (payload: InstallLogicFunctionPayload): Promise<void> => {
|
||||
console.log('Post install logic function executed successfully!', payload.previousVersion);
|
||||
};
|
||||
|
||||
export default definePostInstallLogicFunction({
|
||||
universalIdentifier: '<generated-uuid>',
|
||||
name: 'post-install',
|
||||
description: 'Runs after installation to set up the application.',
|
||||
timeoutSeconds: 300,
|
||||
handler,
|
||||
});
|
||||
```
|
||||
|
||||
Você também pode executar manualmente a função de pós-instalação a qualquer momento usando a CLI:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty function:execute --postInstall
|
||||
```
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* As funções de pós-instalação usam `definePostInstallLogicFunction()` — uma variante especializada que omite as configurações de gatilho (`cronTriggerSettings`, `databaseEventTriggerSettings`, `httpRouteTriggerSettings`, `isTool`).
|
||||
* O manipulador recebe um `InstallLogicFunctionPayload` com `{ previousVersion: string }` — a versão do app que foi instalada anteriormente (ou uma string vazia para instalações novas).
|
||||
* É permitida apenas uma função de pós-instalação por app. A geração do manifesto apresentará erro se mais de uma for detectada.
|
||||
* O `universalIdentifier` da função é definido automaticamente como `postInstallLogicFunctionUniversalIdentifier` no manifesto do aplicativo durante a geração — você não precisa referenciá-lo em `defineApplication()`.
|
||||
* O tempo limite padrão é definido como 300 segundos (5 minutos) para permitir tarefas de configuração mais longas, como o pré-carregamento de dados.
|
||||
* As funções de pós-instalação não precisam de gatilhos — elas são invocadas pela plataforma durante a instalação ou manualmente via `function:execute --postInstall`.
|
||||
|
||||
### Payload de gatilho de rota
|
||||
|
||||
<Warning>
|
||||
**Alteração incompatível (v1.16, janeiro de 2026):** O formato do payload de gatilho de rota mudou. Antes da v1.16, os parâmetros de consulta, parâmetros de caminho e corpo eram enviados diretamente como o payload. A partir da v1.16, eles ficam aninhados dentro de um objeto estruturado `RoutePayload`.
|
||||
|
||||
**Antes da v1.16:**
|
||||
```typescript
|
||||
const handler = async (params) => {
|
||||
const { param1, param2 } = params; // Direct access
|
||||
};
|
||||
```
|
||||
|
||||
**Depois da v1.16:**
|
||||
```typescript
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const { param1, param2 } = event.body; // Access via .body
|
||||
const { queryParam } = event.queryStringParameters;
|
||||
const { id } = event.pathParameters;
|
||||
};
|
||||
```
|
||||
|
||||
**Para migrar funções existentes:** Atualize seu handler para desestruturar de `event.body`, `event.queryStringParameters` ou `event.pathParameters` em vez de diretamente do objeto de parâmetros.
|
||||
</Warning>
|
||||
|
||||
Quando um gatilho de rota invoca sua função de lógica, ela recebe um objeto `RoutePayload` que segue o formato do AWS HTTP API v2. Importe o tipo de `twenty-sdk`:
|
||||
|
||||
```typescript
|
||||
import { defineLogicFunction, type RoutePayload } from 'twenty-sdk';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
// Access request data
|
||||
const { headers, queryStringParameters, pathParameters, body } = event;
|
||||
|
||||
// HTTP method and path are available in requestContext
|
||||
const { method, path } = event.requestContext.http;
|
||||
|
||||
return { message: 'Success' };
|
||||
};
|
||||
```
|
||||
|
||||
O tipo `RoutePayload` tem a seguinte estrutura:
|
||||
|
||||
| Propriedade | Tipo | Descrição |
|
||||
| ---------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | Cabeçalhos HTTP (apenas aqueles listados em `forwardedRequestHeaders`) |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Parâmetros de query string (valores múltiplos unidos por vírgulas) |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Parâmetros de caminho extraídos do padrão de rota (por exemplo, `/users/:id` → `{ id: '123' }`) |
|
||||
| `body` | `object \| null` | Corpo da requisição analisado (JSON) |
|
||||
| `isBase64Encoded` | `boolean` | Se o corpo está codificado em base64 |
|
||||
| `requestContext.http.method` | `string` | Método HTTP (GET, POST, PUT, PATCH, DELETE) |
|
||||
| `requestContext.http.path` | `string` | Caminho bruto da requisição |
|
||||
|
||||
### Encaminhamento de cabeçalhos HTTP
|
||||
|
||||
Por padrão, os cabeçalhos HTTP das requisições recebidas **não** são repassados para sua função de lógica por motivos de segurança. Para acessar cabeçalhos específicos, liste-os explicitamente no array `forwardedRequestHeaders`:
|
||||
|
||||
```typescript
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
|
||||
name: 'webhook-handler',
|
||||
handler,
|
||||
triggers: [
|
||||
{
|
||||
universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6',
|
||||
type: 'route',
|
||||
path: '/webhook',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: false,
|
||||
forwardedRequestHeaders: ['x-webhook-signature', 'content-type'],
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
No seu handler, você pode então acessar esses cabeçalhos:
|
||||
|
||||
```typescript
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const signature = event.headers['x-webhook-signature'];
|
||||
const contentType = event.headers['content-type'];
|
||||
|
||||
// Validate webhook signature...
|
||||
return { received: true };
|
||||
};
|
||||
```
|
||||
|
||||
<Note>
|
||||
Os nomes dos cabeçalhos são normalizados para minúsculas. Acesse-os usando chaves em minúsculas (por exemplo, `event.headers['content-type']`).
|
||||
</Note>
|
||||
|
||||
Você pode criar novas funções de duas formas:
|
||||
|
||||
* **Gerado automaticamente**: Execute `yarn twenty entity:add` e escolha a opção para adicionar uma nova função de lógica. Isso gera um arquivo inicial com um handler e configuração.
|
||||
* **Manual**: Crie um novo arquivo `*.logic-function.ts` e use `defineLogicFunction()`, seguindo o mesmo padrão.
|
||||
|
||||
### Marcar uma função lógica como ferramenta
|
||||
|
||||
Funções lógicas podem ser expostas como **ferramentas** para agentes de IA e fluxos de trabalho. Quando uma função é marcada como ferramenta, ela fica disponível para os recursos de IA do Twenty e pode ser selecionada como uma etapa em automações de fluxos de trabalho.
|
||||
|
||||
Para marcar uma função lógica como ferramenta, defina `isTool: true` e forneça um `toolInputSchema` descrevendo os parâmetros de entrada esperados usando [JSON Schema](https://json-schema.org/):
|
||||
|
||||
```typescript
|
||||
// src/logic-functions/enrich-company.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/generated';
|
||||
|
||||
const handler = async (params: { companyName: string; domain?: string }) => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
const result = await client.mutation({
|
||||
createTask: {
|
||||
__args: {
|
||||
data: {
|
||||
title: `Enrich data for ${params.companyName}`,
|
||||
body: `Domain: ${params.domain ?? 'unknown'}`,
|
||||
},
|
||||
},
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
return { taskId: result.createTask.id };
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
|
||||
name: 'enrich-company',
|
||||
description: 'Enrich a company record with external data',
|
||||
timeoutSeconds: 10,
|
||||
handler,
|
||||
isTool: true,
|
||||
toolInputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
companyName: {
|
||||
type: 'string',
|
||||
description: 'The name of the company to enrich',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
description: 'The company website domain (optional)',
|
||||
},
|
||||
},
|
||||
required: ['companyName'],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* **`isTool`** (`boolean`, padrão: `false`): Quando definido como `true`, a função é registrada como uma ferramenta e fica disponível para agentes de IA e automações de fluxos de trabalho.
|
||||
* **`toolInputSchema`** (`object`, opcional): Um objeto JSON Schema que descreve os parâmetros que sua função aceita. Os agentes de IA usam esse esquema para entender quais entradas a ferramenta espera e para validar as chamadas. Se omitido, o esquema tem como padrão `{ type: 'object', properties: {} }` (sem parâmetros).
|
||||
* Funções com `isTool: false` (ou não definido) **não** são expostas como ferramentas. Elas ainda podem ser executadas diretamente ou chamadas por outras funções, mas não aparecerão na descoberta de ferramentas.
|
||||
* **Nomenclatura de ferramentas**: Quando exposta como uma ferramenta, o nome da função é automaticamente normalizado para `logic_function_<name>` (em minúsculas, caracteres não alfanuméricos substituídos por sublinhados). Por exemplo, `enrich-company` torna-se `logic_function_enrich_company`.
|
||||
* Você pode combinar `isTool` com gatilhos — uma função pode ser ao mesmo tempo uma ferramenta (chamável por agentes de IA) e acionada por eventos (cron, eventos de banco de dados, rotas) simultaneamente.
|
||||
|
||||
<Note>
|
||||
**Escreva uma boa `description`.** Os agentes de IA dependem do campo `description` da função para decidir quando usar a ferramenta. Seja específico sobre o que a ferramenta faz e quando ela deve ser chamada.
|
||||
</Note>
|
||||
|
||||
### Componentes de front-end
|
||||
|
||||
Componentes de front-end permitem criar componentes React personalizados que são renderizados na UI do Twenty. Use `defineFrontComponent()` para definir componentes com validação integrada:
|
||||
|
||||
```typescript
|
||||
// src/front-components/my-widget.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
|
||||
const MyWidget = () => {
|
||||
return (
|
||||
<div style={{ padding: '20px', fontFamily: 'sans-serif' }}>
|
||||
<h1>My Custom Widget</h1>
|
||||
<p>This is a custom front component for Twenty.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
||||
name: 'my-widget',
|
||||
description: 'A custom widget component',
|
||||
component: MyWidget,
|
||||
});
|
||||
```
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* Componentes de front-end são componentes React que renderizam em contextos isolados dentro do Twenty.
|
||||
* O campo `component` faz referência ao seu componente React.
|
||||
* Os componentes são compilados e sincronizados automaticamente durante `yarn twenty app:dev`.
|
||||
|
||||
Você pode criar novos componentes de front-end de duas formas:
|
||||
|
||||
* **Gerado automaticamente**: Execute `yarn twenty entity:add` e escolha a opção para adicionar um novo componente de front-end.
|
||||
* **Manual**: Crie um novo arquivo `.tsx` e use `defineFrontComponent()`, seguindo o mesmo padrão.
|
||||
|
||||
### Habilidades
|
||||
|
||||
As habilidades definem instruções e capacidades reutilizáveis que os agentes de IA podem usar no seu espaço de trabalho. Use `defineSkill()` para definir habilidades com validação integrada:
|
||||
|
||||
```typescript
|
||||
// src/skills/example-skill.ts
|
||||
import { defineSkill } from 'twenty-sdk';
|
||||
|
||||
export default defineSkill({
|
||||
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
||||
name: 'sales-outreach',
|
||||
label: 'Sales Outreach',
|
||||
description: 'Guides the AI agent through a structured sales outreach process',
|
||||
icon: 'IconBrain',
|
||||
content: `You are a sales outreach assistant. When reaching out to a prospect:
|
||||
1. Research the company and recent news
|
||||
2. Identify the prospect's role and likely pain points
|
||||
3. Draft a personalized message referencing specific details
|
||||
4. Keep the tone professional but conversational`,
|
||||
});
|
||||
```
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* `name` é uma string de identificador exclusivo para a habilidade (recomenda-se kebab-case).
|
||||
* `label` é o nome de exibição legível por humanos mostrado na UI.
|
||||
* `content` contém as instruções da habilidade — este é o texto que o agente de IA usa.
|
||||
* `icon` (opcional) define o ícone exibido na UI.
|
||||
* `description` (opcional) fornece contexto adicional sobre a finalidade da habilidade.
|
||||
|
||||
Você pode criar novas habilidades de duas formas:
|
||||
|
||||
* **Gerado automaticamente**: Execute `yarn twenty entity:add` e escolha a opção para adicionar uma nova habilidade.
|
||||
* **Manual**: Crie um novo arquivo e use `defineSkill()`, seguindo o mesmo padrão.
|
||||
|
||||
### Clientes tipados gerados
|
||||
|
||||
Dois clientes tipados são gerados automaticamente pelo `yarn twenty app:dev` e armazenados em `node_modules/twenty-sdk/generated` com base no esquema do seu espaço de trabalho:
|
||||
|
||||
* **`CoreApiClient`** — consulta o endpoint `/graphql` para dados do espaço de trabalho
|
||||
* **`MetadataApiClient`** — consulta o endpoint `/metadata` para obter a configuração do espaço de trabalho e o carregamento de arquivos
|
||||
|
||||
```typescript
|
||||
import { CoreApiClient, MetadataApiClient } from 'twenty-sdk/generated';
|
||||
|
||||
const client = new CoreApiClient();
|
||||
const { me } = await client.query({ me: { id: true, displayName: true } });
|
||||
|
||||
const metadataClient = new MetadataApiClient();
|
||||
const { currentWorkspace } = await metadataClient.query({ currentWorkspace: { id: true } });
|
||||
```
|
||||
|
||||
Ambos os clientes são regenerados automaticamente pelo `yarn twenty app:dev` sempre que seus objetos ou campos forem alterados.
|
||||
|
||||
#### Credenciais em tempo de execução em funções de lógica
|
||||
|
||||
Quando sua função é executada no Twenty, a plataforma injeta credenciais como variáveis de ambiente antes da execução do seu código:
|
||||
|
||||
* `TWENTY_API_URL`: URL base da API do Twenty que seu aplicativo usa como alvo.
|
||||
* `TWENTY_API_KEY`: Chave de curta duração com escopo para o papel de função padrão do seu aplicativo.
|
||||
|
||||
Notas:
|
||||
|
||||
* Você não precisa passar a URL ou a chave de API para o cliente gerado. Ele lê `TWENTY_API_URL` e `TWENTY_API_KEY` de process.env em tempo de execução.
|
||||
* As permissões da chave de API são determinadas pelo papel referenciado no seu `application-config.ts` via `defaultRoleUniversalIdentifier`. Este é o papel padrão usado pelas funções de lógica do seu app.
|
||||
* Os aplicativos podem definir papéis para seguir o princípio do menor privilégio. Conceda apenas as permissões de que suas funções precisam e, em seguida, aponte `defaultRoleUniversalIdentifier` para o identificador universal desse papel.
|
||||
|
||||
#### Carregamento de arquivos
|
||||
|
||||
O `MetadataApiClient` gerado inclui um método `uploadFile` para anexar arquivos a campos do tipo arquivo nos objetos do seu espaço de trabalho. Como os clientes GraphQL padrão não suportam nativamente o carregamento de arquivos multipart, o cliente fornece este método dedicado que implementa, nos bastidores, a [especificação de solicitações multipart do GraphQL](https://github.com/jaydenseric/graphql-multipart-request-spec).
|
||||
|
||||
```typescript
|
||||
import { MetadataApiClient } from 'twenty-sdk/generated';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const metadataClient = new MetadataApiClient();
|
||||
|
||||
const fileBuffer = fs.readFileSync('./invoice.pdf');
|
||||
|
||||
const uploadedFile = await metadataClient.uploadFile(
|
||||
fileBuffer, // file contents as a Buffer
|
||||
'invoice.pdf', // filename
|
||||
'application/pdf', // MIME type (defaults to 'application/octet-stream')
|
||||
'58a0a314-d7ea-4865-9850-7fb84e72f30b', // field universal identifier
|
||||
);
|
||||
|
||||
console.log(uploadedFile);
|
||||
// { id: '...', path: '...', size: 12345, createdAt: '...', url: 'https://...' }
|
||||
```
|
||||
|
||||
A assinatura do método:
|
||||
|
||||
```typescript
|
||||
uploadFile(
|
||||
fileBuffer: Buffer,
|
||||
filename: string,
|
||||
contentType: string,
|
||||
fieldMetadataUniversalIdentifier: string,
|
||||
): Promise<{ id: string; path: string; size: number; createdAt: string; url: string }>
|
||||
```
|
||||
|
||||
| Parâmetro | Tipo | Descrição |
|
||||
| ---------------------------------- | -------- | ------------------------------------------------------------------------ |
|
||||
| `fileBuffer` | `Buffer` | O conteúdo bruto do arquivo |
|
||||
| `filename` | `string` | O nome do arquivo (usado para armazenamento e exibição) |
|
||||
| `contentType` | `string` | Tipo MIME do arquivo (padrão para `application/octet-stream` se omitido) |
|
||||
| `fieldMetadataUniversalIdentifier` | `string` | O `universalIdentifier` do campo do tipo arquivo no seu objeto |
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* O método `uploadFile` está disponível no `MetadataApiClient` porque a mutação de upload é resolvida pelo endpoint `/metadata`.
|
||||
* Ele usa o `universalIdentifier` do campo (não o ID específico do espaço de trabalho), de modo que seu código de upload funcione em qualquer espaço de trabalho onde seu app esteja instalado — consistente com a forma como os apps referenciam campos em qualquer outro lugar.
|
||||
* A `url` retornada é um URL assinado que você pode usar para acessar o arquivo enviado.
|
||||
|
||||
### Exemplo Hello World
|
||||
|
||||
Explore um exemplo mínimo de ponta a ponta que demonstra objetos, funções de lógica, componentes de front-end e vários gatilhos [aqui](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/hello-world).
|
||||
@@ -0,0 +1,233 @@
|
||||
---
|
||||
title: Primeiros passos
|
||||
description: Crie seu primeiro app do Twenty em minutos.
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Os aplicativos estão atualmente em testes alfa. O recurso é funcional, mas ainda está evoluindo.
|
||||
</Warning>
|
||||
|
||||
Os apps permitem que você estenda o Twenty com objetos, campos, funções de lógica, habilidades de IA e componentes de UI personalizados — tudo gerenciado como código.
|
||||
|
||||
**O que você pode fazer hoje:**
|
||||
|
||||
* Defina objetos e campos personalizados como código (modelo de dados gerenciado)
|
||||
* Crie funções de lógica com gatilhos personalizados (rotas HTTP, cron, eventos de banco de dados)
|
||||
* Defina habilidades para agentes de IA
|
||||
* Crie componentes de front-end que renderizam dentro da UI do Twenty
|
||||
* Implemente o mesmo aplicativo em vários espaços de trabalho
|
||||
|
||||
## Pré-requisitos
|
||||
|
||||
* Node.js 24+ e Yarn 4
|
||||
* Um espaço de trabalho do Twenty e uma chave de API (crie uma em https://app.twenty.com/settings/api-webhooks)
|
||||
|
||||
## Primeiros passos
|
||||
|
||||
Crie um novo aplicativo usando o gerador oficial, depois autentique-se e comece a desenvolver:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Scaffold a new app (includes all examples by default)
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
cd my-twenty-app
|
||||
|
||||
# Start dev mode: automatically syncs local changes to your workspace
|
||||
yarn twenty app:dev
|
||||
```
|
||||
|
||||
O gerador de estrutura oferece suporte a dois modos para controlar quais arquivos de exemplo são incluídos:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Default (exhaustive): all examples (object, field, logic function, front component, view, navigation menu item, skill)
|
||||
npx create-twenty-app@latest my-app
|
||||
|
||||
# Minimal: only core files (application-config.ts and default-role.ts)
|
||||
npx create-twenty-app@latest my-app --minimal
|
||||
```
|
||||
|
||||
A partir daqui você pode:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new entity to your application (guided)
|
||||
yarn twenty entity:add
|
||||
|
||||
# Watch your application's function logs
|
||||
yarn twenty function:logs
|
||||
|
||||
# Execute a function by name
|
||||
yarn twenty function:execute -n my-function -p '{"name": "test"}'
|
||||
|
||||
# Execute the pre-install function
|
||||
yarn twenty function:execute --preInstall
|
||||
|
||||
# Execute the post-install function
|
||||
yarn twenty function:execute --postInstall
|
||||
|
||||
# Uninstall the application from the current workspace
|
||||
yarn twenty app:uninstall
|
||||
|
||||
# Display commands' help
|
||||
yarn twenty help
|
||||
```
|
||||
|
||||
Veja também: as páginas de referência da CLI para [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) e [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
|
||||
|
||||
## Estrutura do projeto (com scaffold)
|
||||
|
||||
Ao executar `npx create-twenty-app@latest my-twenty-app`, o gerador:
|
||||
|
||||
* Copia um aplicativo base mínimo para `my-twenty-app/`
|
||||
* Adiciona uma dependência local `twenty-sdk` e a configuração do Yarn 4
|
||||
* Cria arquivos de configuração e scripts conectados à CLI `twenty`
|
||||
* Gera arquivos principais (configuração da aplicação, papel padrão para funções de lógica, funções de pré-instalação e pós-instalação) além de arquivos de exemplo com base no modo de geração de estrutura
|
||||
|
||||
Um app recém-criado com o modo padrão `--exhaustive` fica assim:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
package.json
|
||||
yarn.lock
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
README.md
|
||||
public/ # Public assets folder (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required - main application configuration
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── pre-install.ts # Pre-install logic function
|
||||
│ └── post-install.ts # Post-install logic function
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
└── skills/
|
||||
└── example-skill.ts # Example AI agent skill definition
|
||||
```
|
||||
|
||||
Com `--minimal`, apenas os arquivos principais são criados (`application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` e `logic-functions/post-install.ts`).
|
||||
|
||||
Em alto nível:
|
||||
|
||||
* **package.json**: Declara o nome do app, versão, engines (Node 24+, Yarn 4), e adiciona `twenty-sdk` além de um script `twenty` que delega para a CLI `twenty` local. Execute `yarn twenty help` para listar todos os comandos disponíveis.
|
||||
* **.gitignore**: Ignora artefatos comuns como `node_modules`, `.yarn`, `generated/` (cliente tipado), `dist/`, `build/`, pastas de cobertura, arquivos de log e arquivos `.env*`.
|
||||
* **yarn.lock**, **.yarnrc.yml**, **.yarn/**: Bloqueiam e configuram a ferramenta Yarn 4 usada pelo projeto.
|
||||
* **.nvmrc**: Fixa a versão do Node.js esperada pelo projeto.
|
||||
* **.oxlintrc.json** e **tsconfig.json**: Fornecem lint e configuração do TypeScript para os fontes TypeScript do seu aplicativo.
|
||||
* **README.md**: Um README curto na raiz do aplicativo com instruções básicas.
|
||||
* **public/**: Uma pasta para armazenar recursos públicos (imagens, fontes, arquivos estáticos) que serão servidos com sua aplicação. Os arquivos colocados aqui são enviados durante a sincronização e ficam acessíveis em tempo de execução.
|
||||
* **src/**: O local principal onde você define seu aplicativo como código
|
||||
|
||||
### Detecção de entidades
|
||||
|
||||
O SDK detecta entidades analisando seus arquivos TypeScript em busca de chamadas **`export default define<Entity>({...})`**. Cada tipo de entidade tem uma função utilitária correspondente exportada de `twenty-sdk`:
|
||||
|
||||
| Função utilitária | Tipo de entidade |
|
||||
| -------------------------------- | -------------------------------------------------------------------- |
|
||||
| `defineObject` | Definições de objetos personalizados |
|
||||
| `defineLogicFunction` | Definições de funções de lógica |
|
||||
| `definePreInstallLogicFunction` | Função de lógica de pré-instalação (é executada antes da instalação) |
|
||||
| `definePostInstallLogicFunction` | Função de lógica de pós-instalação (é executada após a instalação) |
|
||||
| `defineFrontComponent` | Definições de componentes de front-end |
|
||||
| `defineRole` | Definições de papéis |
|
||||
| `defineField` | Extensões de campos para objetos existentes |
|
||||
| `defineView` | Definições de visualizações salvas |
|
||||
| `defineNavigationMenuItem` | Definições de itens do menu de navegação |
|
||||
| `defineSkill` | Definições de habilidades de agente de IA |
|
||||
|
||||
<Note>
|
||||
**A nomeação de arquivos é flexível.** A detecção de entidades é baseada em AST — o SDK varre seus arquivos fonte em busca do padrão `export default define<Entity>({...})`. Você pode organizar seus arquivos e pastas como quiser. Agrupar por tipo de entidade (por exemplo, `logic-functions/`, `roles/`) é apenas uma convenção para organização do código, não um requisito.
|
||||
</Note>
|
||||
|
||||
Exemplo de uma entidade detectada:
|
||||
|
||||
```typescript
|
||||
// This file can be named anything and placed anywhere in src/
|
||||
import { defineObject, FieldType } from 'twenty-sdk';
|
||||
|
||||
export default defineObject({
|
||||
universalIdentifier: '...',
|
||||
nameSingular: 'postCard',
|
||||
// ... rest of config
|
||||
});
|
||||
```
|
||||
|
||||
Comandos posteriores adicionarão mais arquivos e pastas:
|
||||
|
||||
* `yarn twenty app:dev` irá gerar automaticamente dois clientes de API tipados em `node_modules/twenty-sdk/generated`: `CoreApiClient` (para dados do espaço de trabalho via `/graphql`) e `MetadataApiClient` (para configuração do espaço de trabalho e envio de arquivos via `/metadata`).
|
||||
* `yarn twenty entity:add` adicionará arquivos de definição de entidade em `src/` para seus objetos, funções, componentes de front-end, papéis e habilidades personalizados, entre outros.
|
||||
|
||||
## Autenticação
|
||||
|
||||
Na primeira vez que você executar `yarn twenty auth:login`, será solicitado o seguinte:
|
||||
|
||||
* URL da API (padrão: http://localhost:3000 ou o perfil do seu espaço de trabalho atual)
|
||||
* Chave de API
|
||||
|
||||
Suas credenciais são armazenadas por usuário em `~/.twenty/config.json`. Você pode manter vários perfis e alternar entre eles.
|
||||
|
||||
### Gerenciando espaços de trabalho
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Login interactively (recommended)
|
||||
yarn twenty auth:login
|
||||
|
||||
# Login to a specific workspace profile
|
||||
yarn twenty auth:login --workspace my-custom-workspace
|
||||
|
||||
# List all configured workspaces
|
||||
yarn twenty auth:list
|
||||
|
||||
# Switch the default workspace (interactive)
|
||||
yarn twenty auth:switch
|
||||
|
||||
# Switch to a specific workspace
|
||||
yarn twenty auth:switch production
|
||||
|
||||
# Check current authentication status
|
||||
yarn twenty auth:status
|
||||
```
|
||||
|
||||
Depois que você alternar os espaços de trabalho com `yarn twenty auth:switch`, todos os comandos subsequentes usarão esse espaço de trabalho por padrão. Você ainda pode substituí-lo temporariamente com `--workspace <name>`.
|
||||
|
||||
## Configuração manual (sem o gerador)
|
||||
|
||||
Embora recomendemos usar `create-twenty-app` para a melhor experiência inicial, você também pode configurar um projeto manualmente. Não instale a CLI globalmente. Em vez disso, adicione `twenty-sdk` como uma dependência local e configure um único script no seu package.json:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add -D twenty-sdk
|
||||
```
|
||||
|
||||
Em seguida, adicione um script `twenty`:
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"twenty": "twenty"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Agora você pode executar todos os comandos via `yarn twenty <command>`, por exemplo, `yarn twenty app:dev`, `yarn twenty help`, etc.
|
||||
|
||||
## Resolução de Problemas
|
||||
|
||||
* Erros de autenticação: execute `yarn twenty auth:login` e certifique-se de que sua chave de API tenha as permissões necessárias.
|
||||
* Não é possível conectar ao servidor: verifique a URL da API e se o servidor do Twenty está acessível.
|
||||
* Tipos ou cliente ausentes/desatualizados: reinicie `yarn twenty app:dev` — ele gera automaticamente o cliente tipado.
|
||||
* Modo de desenvolvimento não sincronizando: certifique-se de que `yarn twenty app:dev` esteja em execução e de que as alterações não estejam sendo ignoradas pelo seu ambiente.
|
||||
|
||||
Canal de ajuda no Discord: https://discord.com/channels/1130383047699738754/1130386664812982322
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: Publicação
|
||||
description: Distribua seu aplicativo Twenty no Marketplace ou implante-o internamente.
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Os aplicativos estão atualmente em testes alfa. O recurso é funcional, mas ainda está evoluindo.
|
||||
</Warning>
|
||||
|
||||
## Visão Geral
|
||||
|
||||
Depois que seu aplicativo estiver [compilado e testado localmente](/l/pt/developers/extend/apps/building), você tem dois caminhos para distribuí-lo:
|
||||
|
||||
* **Publicar no npm** — liste seu aplicativo no Marketplace da Twenty para que qualquer espaço de trabalho possa descobrir e instalar.
|
||||
* **Enviar um tarball** — implante seu aplicativo em um servidor Twenty específico para uso interno sem torná-lo público.
|
||||
|
||||
## Publicação no npm
|
||||
|
||||
Publicar no npm torna seu aplicativo descobrível no Marketplace da Twenty. Qualquer espaço de trabalho da Twenty pode navegar, instalar e atualizar aplicativos do Marketplace diretamente pela UI.
|
||||
|
||||
### Requisitos
|
||||
|
||||
* Uma conta no [npm](https://www.npmjs.com)
|
||||
* O nome do seu pacote **deve** usar o prefixo `twenty-app-` (por exemplo, `twenty-app-postcard-sender`)
|
||||
|
||||
### Etapas
|
||||
|
||||
1. **Compile seu aplicativo** — a CLI compila seus códigos-fonte TypeScript e gera o manifesto do aplicativo:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty app:build
|
||||
```
|
||||
|
||||
2. **Publicar no npm** — envie o pacote compilado para o registro do npm:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx twenty app:publish
|
||||
```
|
||||
|
||||
### Descoberta automática
|
||||
|
||||
Pacotes com o prefixo `twenty-app-` são detectados automaticamente pelo catálogo do Marketplace da Twenty. Depois de publicado, seu aplicativo aparece no Marketplace em poucos minutos — sem necessidade de registro manual ou aprovação.
|
||||
|
||||
### Publicação via CI
|
||||
|
||||
O projeto gerado inclui um workflow do GitHub Actions que publica a cada lançamento. Ele executa `app:build` e depois `npm publish --provenance` a partir da saída do build:
|
||||
|
||||
```yaml filename=".github/workflows/publish.yml"
|
||||
name: Publish
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
registry-url: https://registry.npmjs.org
|
||||
- run: yarn install --immutable
|
||||
- run: npx twenty app:build
|
||||
- run: npm publish --provenance --access public
|
||||
working-directory: .twenty/output
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
```
|
||||
|
||||
Para outros sistemas de CI (GitLab CI, CircleCI etc.), aplicam-se os mesmos três comandos: `yarn install`, `npx twenty app:build` e depois `npm publish` a partir de `.twenty/output`.
|
||||
|
||||
<Tip>
|
||||
**Proveniência do npm** é opcional, mas recomendada. Publicar com `--provenance` adiciona um selo de confiança à sua listagem no npm, permitindo que os usuários verifiquem que o pacote foi construído a partir de um commit específico em um pipeline de CI público. Consulte a [documentação de proveniência do npm](https://docs.npmjs.com/generating-provenance-statements) para instruções de configuração.
|
||||
</Tip>
|
||||
|
||||
## Distribuição interna
|
||||
|
||||
Para aplicativos que você não quer disponibilizar publicamente — ferramentas proprietárias, integrações apenas para empresas ou builds experimentais — você pode enviar um tarball diretamente para um servidor Twenty.
|
||||
|
||||
### Enviar um tarball
|
||||
|
||||
Compile seu aplicativo e implante-o em um servidor específico em uma única etapa:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx twenty app:publish --server <server-url>
|
||||
```
|
||||
|
||||
Qualquer espaço de trabalho nesse servidor pode então instalar e atualizar o aplicativo na página de configurações de **Aplicativos**.
|
||||
|
||||
### Gerenciamento de versões
|
||||
|
||||
Para lançar uma atualização:
|
||||
|
||||
1. Atualize o campo `version` no seu `package.json`
|
||||
2. Envie um novo tarball com `npx twenty app:publish --server <server-url>`
|
||||
3. Os espaços de trabalho nesse servidor verão a atualização disponível nas suas configurações
|
||||
|
||||
<Note>
|
||||
Aplicativos internos ficam restritos ao servidor para o qual são enviados. Eles não aparecem no Marketplace público e não podem ser instalados por espaços de trabalho em outros servidores.
|
||||
</Note>
|
||||
|
||||
## Categorias de aplicativos
|
||||
|
||||
A Twenty organiza os aplicativos em três categorias com base em como são distribuídos:
|
||||
|
||||
| Categoria | Como Funciona | Visível no Marketplace? |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
|
||||
| **Desenvolvimento** | Aplicativos em modo de desenvolvimento local executados via `yarn twenty app:dev`. Usados para compilação e testes. | Não |
|
||||
| **Publicado** | Aplicativos publicados no npm com o prefixo `twenty-app-`. Listados no Marketplace para que qualquer espaço de trabalho possa instalar. | Sim |
|
||||
| **Interno** | Aplicativos implantados via tarball em um servidor específico. Disponível apenas para espaços de trabalho nesse servidor. | Não |
|
||||
|
||||
<Tip>
|
||||
Comece no modo de **Desenvolvimento** enquanto cria seu aplicativo. Quando estiver pronto, escolha **Publicado** (npm) para ampla distribuição ou **Interno** (tarball) para implantação privada.
|
||||
</Tip>
|
||||
@@ -321,11 +321,11 @@ Você pode substituir os campos padrão definindo um campo com o mesmo nome no s
|
||||
mas isso não é recomendado.
|
||||
</Note>
|
||||
|
||||
### Defining fields on existing objects
|
||||
### Definindo campos em objetos existentes
|
||||
|
||||
Use `defineField()` to add custom fields to existing objects — both standard objects (like `company`, `person`, `opportunity`) and custom objects defined by other apps. Each field lives in its own file and references the target object by its `universalIdentifier`.
|
||||
Use `defineField()` para adicionar campos personalizados a objetos existentes — tanto objetos padrão (como `company`, `person`, `opportunity`) quanto objetos personalizados definidos por outros aplicativos. Cada campo fica em seu próprio arquivo e faz referência ao objeto de destino por seu `universalIdentifier`.
|
||||
|
||||
To reference standard objects, import `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` from `twenty-sdk`. This constant provides stable identifiers for all built-in objects and their fields:
|
||||
Para fazer referência a objetos padrão, importe `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` de `twenty-sdk`. Essa constante fornece identificadores estáveis para todos os objetos integrados e seus campos:
|
||||
|
||||
```typescript
|
||||
// src/fields/apollo-total-funding.field.ts
|
||||
@@ -349,22 +349,22 @@ export default defineField({
|
||||
|
||||
Pontos-chave:
|
||||
|
||||
* `objectUniversalIdentifier` tells Twenty which object to attach the field to. Use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.<objectName>.universalIdentifier` for standard objects.
|
||||
* Each field requires its own stable `universalIdentifier`, a `name`, `type`, `label`, and the target `objectUniversalIdentifier`.
|
||||
* You can scaffold new fields using `yarn twenty entity:add` and choosing the field option.
|
||||
* `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` is also exported as `STANDARD_OBJECT` for convenience — both refer to the same constant.
|
||||
* `objectUniversalIdentifier` indica ao Twenty a qual objeto anexar o campo. Use `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.<objectName.universalIdentifier` para objetos padrão.
|
||||
* Cada campo requer seu próprio `universalIdentifier` estável, um `name`, `type`, `label` e o `objectUniversalIdentifier` de destino.
|
||||
* Você pode criar novos campos usando `yarn twenty entity:add` e escolhendo a opção de campo.
|
||||
* `STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS` também é exportado como `STANDARD_OBJECT` por conveniência — ambos se referem à mesma constante.
|
||||
|
||||
Available standard objects include: `attachment`, `blocklist`, `calendarChannel`, `calendarEvent`, `calendarEventParticipant`, `company`, `connectedAccount`, `dashboard`, `favorite`, `favoriteFolder`, `message`, `messageChannel`, `messageParticipant`, `messageThread`, `note`, `noteTarget`, `opportunity`, `person`, `task`, `taskTarget`, `timelineActivity`, `workflow`, `workflowAutomatedTrigger`, `workflowRun`, `workflowVersion`, and `workspaceMember`.
|
||||
Os objetos padrão disponíveis incluem: `attachment`, `blocklist`, `calendarChannel`, `calendarEvent`, `calendarEventParticipant`, `company`, `connectedAccount`, `dashboard`, `favorite`, `favoriteFolder`, `message`, `messageChannel`, `messageParticipant`, `messageThread`, `note`, `noteTarget`, `opportunity`, `person`, `task`, `taskTarget`, `timelineActivity`, `workflow`, `workflowAutomatedTrigger`, `workflowRun`, `workflowVersion` e `workspaceMember`.
|
||||
|
||||
Each standard object also exposes its field identifiers. For example, to reference a specific field on a standard object in role permissions:
|
||||
Cada objeto padrão também expõe os identificadores de seus campos. Por exemplo, para referenciar um campo específico em um objeto padrão nas permissões de função:
|
||||
|
||||
```typescript
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.name.universalIdentifier
|
||||
```
|
||||
|
||||
#### Relation fields on existing objects
|
||||
#### Campos de relação em objetos existentes
|
||||
|
||||
You can also define relation fields that link existing objects to your custom objects:
|
||||
Você também pode definir campos de relação que vinculam objetos existentes aos seus objetos personalizados:
|
||||
|
||||
```typescript
|
||||
// src/fields/people-on-call-recording.field.ts
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
title: Estender
|
||||
description: Amplie a funcionalidade do Twenty com APIs, webhooks e aplicativos personalizados.
|
||||
redirect: /developers/introduction
|
||||
---
|
||||
|
||||
<Frame>
|
||||
@@ -16,18 +15,18 @@ O Twenty foi projetado para ser extensível. Use nossas APIs, webhooks e o frame
|
||||
|
||||
* **APIs**: Consulte e modifique seus dados de CRM programaticamente usando REST ou GraphQL
|
||||
* **Webhooks**: Receba notificações em tempo real quando eventos ocorrerem no Twenty
|
||||
* **Apps**: Crie aplicativos personalizados que expandem as capacidades do Twenty - Em breve!
|
||||
* **Apps**: Crie aplicativos personalizados que expandem as capacidades do Twenty
|
||||
|
||||
## Primeiros passos
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="APIs" icon="código" href="/l/pt/developers/api">
|
||||
<Card title="APIs" icon="código" href="/l/pt/developers/extend/api">
|
||||
Conecte-se ao Twenty programaticamente
|
||||
</Card>
|
||||
<Card title="Webhooks" icon="bell" href="/l/pt/developers/webhooks">
|
||||
<Card title="Webhooks" icon="bell" href="/l/pt/developers/extend/webhooks">
|
||||
Receba notificações de eventos em tempo real
|
||||
</Card>
|
||||
<Card title="Aplicativos" icon="puzzle-piece" href="/l/pt/developers/apps/apps">
|
||||
Crie personalizações como código (Alpha)
|
||||
<Card title="Aplicativos" icon="puzzle-piece" href="/l/pt/developers/extend/apps/getting-started">
|
||||
Crie personalizações como código
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: Webhooks
|
||||
description: Receba notificações em tempo real quando eventos ocorrerem no seu CRM.
|
||||
---
|
||||
|
||||
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
|
||||
|
||||
Os webhooks enviam dados para seus sistemas em tempo real quando eventos ocorrem no Twenty — sem necessidade de polling. Use-os para manter sistemas externos em sincronia, acionar automações ou enviar alertas.
|
||||
|
||||
## Criar Webhook
|
||||
|
||||
1. Vá para **Configurações → APIs & Webhooks → Webhooks**
|
||||
2. Clique em **+ Criar webhook**
|
||||
3. Insira a URL do seu webhook (deve ser publicamente acessível)
|
||||
4. Clique em **Salvar**
|
||||
|
||||
O webhook é ativado imediatamente e começa a enviar notificações.
|
||||
|
||||
<VimeoEmbed videoId="928786708" title="Criando um webhook" />
|
||||
|
||||
### Gerenciar Webhooks
|
||||
|
||||
**Editar**: Clique no webhook → Atualizar URL → **Salvar**
|
||||
|
||||
**Excluir**: Clique no webhook → **Excluir** → Confirmar
|
||||
|
||||
## Eventos
|
||||
|
||||
O Twenty envia webhooks para estes tipos de eventos:
|
||||
|
||||
| Evento | Exemplo |
|
||||
| ----------------------- | ---------------------------------------------------------- |
|
||||
| **Registro criado** | `person.created`, `company.created`, `note.created` |
|
||||
| **Registro atualizado** | `person.updated`, `company.updated`, `opportunity.updated` |
|
||||
| **Registro excluído** | `person.deleted`, `company.deleted` |
|
||||
|
||||
Todos os tipos de evento são enviados para a URL do seu webhook. A filtragem de eventos pode ser adicionada em versões futuras.
|
||||
|
||||
## Formato do payload
|
||||
|
||||
Cada webhook envia um HTTP POST com um corpo JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "person.created",
|
||||
"data": {
|
||||
"id": "abc12345",
|
||||
"firstName": "Alice",
|
||||
"lastName": "Doe",
|
||||
"email": "alice@example.com",
|
||||
"createdAt": "2025-02-10T15:30:45Z",
|
||||
"createdBy": "user_123"
|
||||
},
|
||||
"timestamp": "2025-02-10T15:30:50Z"
|
||||
}
|
||||
```
|
||||
|
||||
| Campo | Descrição |
|
||||
| ----------- | ------------------------------------------------------ |
|
||||
| `event` | O que aconteceu (por exemplo, `person.created`) |
|
||||
| `data` | O registro completo que foi criado/atualizado/excluído |
|
||||
| `timestamp` | Quando o evento ocorreu (UTC) |
|
||||
|
||||
<Note>
|
||||
Responda com um **status HTTP 2xx** (200-299) para confirmar o recebimento. Respostas não 2xx são registradas como falhas de entrega.
|
||||
</Note>
|
||||
|
||||
## Validação de Webhook
|
||||
|
||||
O Twenty assina cada solicitação de webhook por segurança. Valide as assinaturas para garantir que as solicitações sejam autênticas.
|
||||
|
||||
### Cabeçalhos
|
||||
|
||||
| Cabeçalho | Descrição |
|
||||
| ---------------------------- | ------------------------ |
|
||||
| `X-Twenty-Webhook-Signature` | Assinatura HMAC SHA256 |
|
||||
| `X-Twenty-Webhook-Timestamp` | Timestamp da solicitação |
|
||||
|
||||
### Etapas de validação
|
||||
|
||||
1. Obtenha o timestamp de `X-Twenty-Webhook-Timestamp`
|
||||
2. Crie a string: `{timestamp}:{JSON payload}`
|
||||
3. Calcule o HMAC SHA256 usando o segredo do seu webhook
|
||||
4. Compare com `X-Twenty-Webhook-Signature`
|
||||
|
||||
### Exemplo (Node.js)
|
||||
|
||||
```javascript
|
||||
const crypto = require("crypto");
|
||||
|
||||
const timestamp = req.headers["x-twenty-webhook-timestamp"];
|
||||
const payload = JSON.stringify(req.body);
|
||||
const secret = "your-webhook-secret";
|
||||
|
||||
const stringToSign = `${timestamp}:${payload}`;
|
||||
const expectedSignature = crypto
|
||||
.createHmac("sha256", secret)
|
||||
.update(stringToSign)
|
||||
.digest("hex");
|
||||
|
||||
const receivedSignature = req.headers["x-twenty-webhook-signature"];
|
||||
const isValid = crypto.timingSafeEqual(
|
||||
Buffer.from(expectedSignature, "hex"),
|
||||
Buffer.from(receivedSignature, "hex")
|
||||
);
|
||||
```
|
||||
|
||||
## Webhooks vs Fluxos de trabalho
|
||||
|
||||
| Método | Direção | Caso de uso |
|
||||
| ------------------------------------------- | ------- | -------------------------------------------------------------------------------- |
|
||||
| **Webhooks** | SAÍDA | Notificar automaticamente sistemas externos sobre qualquer alteração de registro |
|
||||
| **Fluxo de trabalho + Solicitação HTTP** | SAÍDA | Enviar dados para fora com lógica personalizada (filtros, transformações) |
|
||||
| **Gatilho de webhook de fluxo de trabalho** | ENTRADA | Receber dados no Twenty a partir de sistemas externos |
|
||||
|
||||
Para receber dados externos, consulte [Configurar um gatilho de Webhook](/l/pt/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger).
|
||||
@@ -5,28 +5,18 @@ description: Bem-vindo à Documentação para Desenvolvedores da Twenty, seus re
|
||||
|
||||
import { CardTitle } from "/snippets/card-title.mdx"
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card href="/l/pt/developers/api" icon="code">
|
||||
<CardTitle>API</CardTitle>
|
||||
Consulte e modifique os dados do seu CRM com REST ou GraphQL.
|
||||
<CardGroup cols={3}>
|
||||
<Card href="/l/pt/developers/extend/extend" img="/images/user-guide/integrations/plug.png">
|
||||
<CardTitle>Estender</CardTitle>
|
||||
Crie integrações com APIs, webhooks e aplicativos personalizados.
|
||||
</Card>
|
||||
|
||||
<Card href="/l/pt/developers/webhooks" icon="bell">
|
||||
<CardTitle>Webhooks</CardTitle>
|
||||
Receba notificações em tempo real quando eventos ocorrerem.
|
||||
</Card>
|
||||
|
||||
<Card href="/l/pt/developers/apps/apps" icon="puzzle-piece">
|
||||
<CardTitle>Apps</CardTitle>
|
||||
Crie aplicativos personalizados que estendem as capacidades do Twenty.
|
||||
</Card>
|
||||
|
||||
<Card href="/l/pt/developers/self-host/self-host" icon="desktop">
|
||||
<Card href="/l/pt/developers/self-host/self-host" img="/images/user-guide/what-is-twenty/20.png">
|
||||
<CardTitle>Auto-hospedar</CardTitle>
|
||||
Implante e gerencie o Twenty na sua própria infraestrutura.
|
||||
</Card>
|
||||
|
||||
<Card href="/l/pt/developers/contribute/contribute" icon="github">
|
||||
<Card href="/l/pt/developers/contribute/contribute" img="/images/user-guide/github/github-header.png">
|
||||
<CardTitle>Contribuir</CardTitle>
|
||||
Junte-se à nossa comunidade de código aberto e contribua para o Twenty.
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user