---
title: Funções lógicas
description: Defina funções TypeScript no lado do servidor com gatilhos HTTP, cron e de eventos de banco de dados.
icon: bolt
---

As funções de lógica são funções TypeScript no lado do servidor que são executadas na plataforma Twenty. Elas podem ser acionadas por solicitações HTTP, agendamentos cron ou eventos de banco de dados — e também podem ser expostas como ferramentas para agentes de IA.

<AccordionGroup>
<Accordion title="defineLogicFunction" description="Defina funções de lógica e seus gatilhos">

Cada arquivo de função usa `defineLogicFunction()` para exportar uma configuração com um manipulador e gatilhos opcionais.

```ts src/logic-functions/createPostCard.logic-function.ts
import { defineLogicFunction } from 'twenty-sdk/define';
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk/define';
import { CoreApiClient, type Person } from 'twenty-client-sdk/core';

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,
  httpRouteTriggerSettings: {
    path: '/post-card/create',
    httpMethod: 'GET',
    isAuthRequired: true,
  },
  /*databaseEventTriggerSettings: {
    eventName: 'people.created',
  },*/
  /*cronTriggerSettings: {
    pattern: '0 0 1 1 *',
  },*/
});
```

Tipos de gatilho disponíveis:
* **httpRoute**: Expõe sua função em um caminho e método HTTP **no endpoint `/s/`**:
> por exemplo, `path: '/post-card/create'` é acessível em `https://your-twenty-server.com/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`, `*.created`, `company.*`

<Note>
Você também pode executar manualmente uma função usando a CLI:

```bash filename="Terminal"
yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
```

```bash filename="Terminal"
yarn twenty exec -y e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
```

Você pode acompanhar os logs com:

```bash filename="Terminal"
yarn twenty logs
```
</Note>

#### Payload de gatilho de rota

Quando um gatilho de rota invoca sua função de lógica, ela recebe um objeto `RoutePayload` que segue o [formato HTTP API v2 da AWS](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html).
Importe o tipo `RoutePayload` de `twenty-sdk`:

```ts
import { defineLogicFunction, type RoutePayload } from 'twenty-sdk/define';

const handler = async (event: RoutePayload) => {
  const { headers, queryStringParameters, pathParameters, body } = event;
  const { method, path } = event.requestContext.http;

  return { message: 'Success' };
};
```

O tipo `RoutePayload` tem a seguinte estrutura:

  | Propriedade                  | Tipo                                                    | Descrição                                                                                                                                                                                                                                   | Exemplo                                                                    |
  | ---------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
  | `headers`                    | `Record\<string, string \| undefined>` | Cabeçalhos HTTP (apenas aqueles listados em `forwardedRequestHeaders`)                                                                                                                                                                      | veja a seção abaixo                                                        |
  | `queryStringParameters`      | `Record\<string, string \| undefined>` | Parâmetros de query string (valores múltiplos unidos por vírgulas)                                                                                                                                                                          | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
  | `pathParameters`             | `Record\<string, string \| undefined>` | Parâmetros de caminho extraídos do padrão de rota                                                                                                                                                                                           | `/users/:id`, `/users/123` -> `{ id: '123' }`                              |
  | `body`                       | `object \| null`                                        | Corpo da requisição analisado (JSON)                                                                                                                                                                                                        | `{ id: 1 }` -> `{ id: 1 }`                                                 |
  | `rawBody`                    | `string \| undefined`                                   | Corpo da solicitação UTF-8 original, antes da análise de JSON. Útil para verificar assinaturas de webhook no estilo HMAC (por exemplo, `X-Hub-Signature-256` do GitHub, Stripe). `undefined` quando o ambiente de execução não o preservou. |                                                                            |
  | `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                                                                                                                                                                                                                 |                                                                            |


#### forwardedRequestHeaders

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`:

```ts
export default defineLogicFunction({
  universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
  name: 'webhook-handler',
  handler,
  httpRouteTriggerSettings: {
    path: '/webhook',
    httpMethod: 'POST',
    isAuthRequired: false,
    forwardedRequestHeaders: ['x-webhook-signature', 'content-type'],
  },
});
```

No seu manipulador, acesse os cabeçalhos encaminhados assim:

```ts
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>

#### Expor uma função como ferramenta de IA ou como ação de fluxo de trabalho

As funções de lógica podem ser expostas em duas superfícies, cada uma com seu próprio gatilho:

* **`toolTriggerSettings`** — torna a função disponível para os recursos de IA do Twenty (chat, MCP, chamadas de função). Usa o JSON Schema padrão, o formato que os LLMs entendem nativamente.
* **`workflowActionTriggerSettings`** — torna a função visível como uma etapa no construtor visual de fluxos de trabalho. Usa o `InputSchema` avançado do Twenty para que o construtor possa renderizar editores de campo adequados, seletores de variáveis e rótulos.

Uma função pode optar por uma, pela outra ou por ambas. Ficam ao lado de `cronTriggerSettings`, `databaseEventTriggerSettings` e `httpRouteTriggerSettings` — mesmo padrão, mesmo formato.

```ts src/logic-functions/enrich-company.logic-function.ts
import { defineLogicFunction } from 'twenty-sdk/define';
import { CoreApiClient } from 'twenty-client-sdk/core';

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,
  toolTriggerSettings: {},
});
```

Pontos-chave:

* Uma função pode misturar superfícies — declare tanto `toolTriggerSettings` quanto `workflowActionTriggerSettings` para expô-la no chat E no construtor de fluxos de trabalho.
* `toolTriggerSettings.inputSchema` e `workflowActionTriggerSettings.inputSchema` são opcionais. Quando omitidos, o construtor de manifestos os infere a partir do código-fonte do handler (JSON Schema para a ferramenta de IA, `InputSchema` do Twenty para a ação de fluxo de trabalho). Forneça um explicitamente quando quiser uma tipagem mais rica — por exemplo, com campos compatíveis com `FieldMetadataType`, como `CURRENCY` ou `RELATION` para o construtor de fluxos de trabalho, ou com campos `description` que o agente de IA pode ler:

```ts
export default defineLogicFunction({
  ...,
  toolTriggerSettings: {
    inputSchema: {
      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'],
    },
  },
});
```

<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>

</Accordion>
<Accordion title="definePostInstallLogicFunction" description="Defina uma função de lógica de pós-instalação (uma por aplicativo)">

Uma função de pós-instalação é uma função lógica que é executada automaticamente assim que seu aplicativo terminar de ser instalado em um espaço de trabalho. O servidor a executa **depois** que os metadados do aplicativo forem sincronizados e o cliente do SDK for gerado, para que o espaço de trabalho esteja totalmente pronto para uso e o novo esquema esteja disponível. Casos de uso típicos incluem popular dados padrão, criar registros iniciais, configurar as definições do espaço de trabalho ou provisionar recursos em serviços de terceiros.

```ts src/logic-functions/post-install.ts
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';

const handler = async (payload: InstallPayload): Promise<void> => {
  console.log('Post install logic function executed successfully!', payload.previousVersion);
};

export default definePostInstallLogicFunction({
  universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
  name: 'post-install',
  description: 'Runs after installation to set up the application.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: false,
  shouldRunSynchronously: false,
  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 exec --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`, `toolTriggerSettings`, `workflowActionTriggerSettings`).
* O manipulador recebe um `InstallPayload` com `{ previousVersion?: string; newVersion: string }` — `newVersion` é a versão que está sendo instalada, e `previousVersion` é a versão que foi instalada anteriormente (ou `undefined` em uma instalação nova). Use esses valores para distinguir instalações novas de atualizações e para executar lógica de migração específica da versão.
* **Quando o hook é executado**: apenas em instalações novas, por padrão. Passe `shouldRunOnVersionUpgrade: true` se você também quiser que ele seja executado quando o app for atualizado a partir de uma versão anterior. Quando omitida, a flag tem valor padrão `false` e as atualizações ignoram o hook.
* **Modelo de execução — assíncrono por padrão, síncrono opcional**: a flag `shouldRunSynchronously` controla *como* a pós-instalação é executada.
  * `shouldRunSynchronously: false` *(padrão)* — o hook é **enfileirado na fila de mensagens** com `retryLimit: 3` e é executado de forma assíncrona em um worker. A resposta da instalação retorna assim que o job é enfileirado, então um manipulador lento ou com falha não bloqueia quem chamou. O worker tentará novamente até três vezes. **Use isto para jobs de longa duração** — popular grandes conjuntos de dados, chamar APIs de terceiros lentas, provisionar recursos externos, qualquer coisa que possa exceder uma janela razoável de resposta HTTP.
  * `shouldRunSynchronously: true` — o hook é executado **inline durante o fluxo de instalação** (mesmo executor da pré-instalação). A requisição de instalação bloqueia até o manipulador terminar e, se ele lançar uma exceção, quem chamou a instalação recebe um `POST_INSTALL_ERROR`. Sem novas tentativas automáticas. **Use isto para trabalhos rápidos que precisam ser concluídos antes da resposta** — por exemplo, emitir um erro de validação para o usuário ou fazer uma configuração rápida da qual o cliente dependerá imediatamente após a chamada de instalação retornar. Tenha em mente que a migração de metadados já foi aplicada quando a pós-instalação é executada, então uma falha no modo síncrono **não** reverte as alterações de esquema — ela apenas expõe o erro.
* Garanta que seu manipulador seja idempotente. No modo assíncrono, a fila pode tentar novamente até três vezes; em qualquer modo, o hook pode ser executado novamente em atualizações quando `shouldRunOnVersionUpgrade: true`.
* As variáveis de ambiente `APPLICATION_ID`, `APP_ACCESS_TOKEN` e `API_URL` estão disponíveis dentro do manipulador (assim como em qualquer outra função de lógica), então você pode chamar a API da Twenty com um token de acesso de aplicativo com escopo para o seu app.
* É 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`, `shouldRunOnVersionUpgrade` e `shouldRunSynchronously` da função são anexados automaticamente ao manifesto do aplicativo no campo `postInstallLogicFunction` durante o build — você não precisa referenciá-los 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.
* **Não executado no modo de desenvolvimento**: quando um app é registrado localmente (via `yarn twenty dev`), o servidor pula completamente o fluxo de instalação e sincroniza arquivos diretamente pelo watcher da CLI — portanto, a pós-instalação nunca é executada no modo de desenvolvimento, independentemente de `shouldRunSynchronously`. Use `yarn twenty exec --postInstall` para acioná-lo manualmente em um workspace em execução.

</Accordion>
<Accordion title="definePreInstallLogicFunction" description="Defina uma função de lógica de pré-instalação (uma por aplicativo)">

Uma função de pré-instalação é uma função de lógica que é executada automaticamente durante a instalação, **antes que a migração de metadados do workspace seja aplicada**. Ela compartilha o mesmo formato de payload que a pós-instalação (`InstallPayload`), mas está posicionada mais cedo no fluxo de instalação para poder preparar o estado do qual a próxima migração depende — usos típicos incluem fazer backup de dados, validar a compatibilidade com o novo esquema ou arquivar registros que estão prestes a ser reestruturados ou removidos.

```ts src/logic-functions/pre-install.ts
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';

const handler = async (payload: InstallPayload): Promise<void> => {
  console.log('Pre install logic function executed successfully!', payload.previousVersion);
};

export default definePreInstallLogicFunction({
  universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
  name: 'pre-install',
  description: 'Runs before installation to prepare the application.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: true,
  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 exec --preInstall
```

Pontos-chave:
* Funções de pré-instalação usam `definePreInstallLogicFunction()` — a mesma configuração especializada da pós-instalação, apenas anexada a um ponto diferente do ciclo de vida.
* Os manipuladores de pré e pós-instalação recebem o mesmo tipo `InstallPayload`: `{ previousVersion?: string; newVersion: string }`. Importe-o uma vez e reutilize-o para ambos os hooks.
* **Quando o hook é executado**: posicionado imediatamente antes da migração de metadados do workspace (`synchronizeFromManifest`). Antes de executar, o servidor realiza uma "sincronização simplificada" puramente aditiva que registra a função de pré-instalação da **nova** versão nos metadados do workspace — nada mais é alterado — e então a executa. Como essa sincronização é apenas aditiva, os objetos, campos e dados da versão anterior ainda estão intactos quando seu manipulador é executado: você pode ler e fazer backup com segurança do estado pré-migração.
* **Modelo de execução**: a pré-instalação é executada **de forma síncrona** e **bloqueia a instalação**. Se o manipulador lançar uma exceção, a instalação é abortada antes que quaisquer alterações de esquema sejam aplicadas — o workspace permanece na versão anterior em um estado consistente. Isto é intencional: a pré-instalação é sua última chance de recusar uma atualização arriscada.
* Assim como na pós-instalação, é permitida apenas uma função de pré-instalação por app. Ela é anexada ao manifesto do aplicativo sob `preInstallLogicFunction` automaticamente durante o build.
* **Não é executada no modo de desenvolvimento**: igual à pós-instalação — o fluxo de instalação é totalmente ignorado para apps registrados localmente, portanto a pré-instalação nunca é executada com `yarn twenty dev`. Use `yarn twenty exec --preInstall` para acioná-lo manualmente.

</Accordion>
<Accordion title="Pré-instalação vs pós-instalação: quando usar cada um" description="Escolhendo o hook de instalação correto">

Ambos os hooks fazem parte do mesmo fluxo de instalação e recebem o mesmo `InstallPayload`. A diferença é **quando** eles são executados em relação à migração de metadados do workspace, e isso muda quais dados eles podem manipular com segurança.

```
┌─────────────────────────────────────────────────────────────┐
│ install flow                                                │
│                                                             │
│   upload package → [pre-install] → metadata migration →     │
│   generate SDK → [post-install]                             │
│                                                             │
│                  old schema visible    new schema visible   │
└─────────────────────────────────────────────────────────────┘
```

A pré-instalação é sempre **síncrona** (ela bloqueia a instalação e pode abortá-la). A pós-instalação é **assíncrona por padrão** — enfileirada em um worker com novas tentativas automáticas — mas pode optar por execução síncrona com `shouldRunSynchronously: true`. Veja o acordeão `definePostInstallLogicFunction` acima para saber quando usar cada modo.

**Use `post-install` para qualquer coisa que precise que o novo esquema exista.** Este é o caso mais comum:

* Popular dados padrão (criando registros iniciais, visualizações padrão, conteúdo de demonstração) em objetos e campos recém-adicionados.
* Registrar webhooks com serviços de terceiros agora que o app tem suas credenciais.
* Chamar sua própria API para finalizar a configuração que depende dos metadados sincronizados.
* Lógica idempotente de "garantir que isso exista" que deve reconciliar o estado em cada atualização — combine com `shouldRunOnVersionUpgrade: true`.

Exemplo — popular um registro `PostCard` padrão após a instalação:

```ts src/logic-functions/post-install.ts
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
import { createClient } from './generated/client';

const handler = async ({ previousVersion }: InstallPayload): Promise<void> => {
  if (previousVersion) return; // fresh installs only

  const client = createClient();
  await client.postCard.create({
    data: { title: 'Welcome to Postcard', content: 'Your first card!' },
  });
};

export default definePostInstallLogicFunction({
  universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
  name: 'post-install',
  description: 'Seeds a welcome post card after install.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: false,
  handler,
});
```

**Use `pre-install` quando uma migração, de outra forma, destruiria ou corromperia dados existentes.** Como a pré-instalação roda contra o esquema *anterior* e sua falha reverte a atualização, é o lugar certo para qualquer coisa arriscada:

* **Fazer backup de dados que estão prestes a ser removidos ou reestruturados** — por exemplo, você está removendo um campo na v2 e precisa copiar seus valores para outro campo ou exportá-los para um armazenamento antes que a migração seja executada.
* **Arquivar registros que uma nova restrição invalidaria** — por exemplo, um campo está se tornando `NOT NULL` e você precisa excluir ou corrigir linhas com valores nulos primeiro.
* **Validar a compatibilidade e recusar a atualização se os dados atuais não puderem ser migrados de forma limpa** — lance uma exceção no manipulador e a instalação é abortada sem alterações aplicadas. Isto é mais seguro do que descobrir a incompatibilidade no meio da migração.
* **Renomear ou reatribuir chaves de dados** antes de uma alteração de esquema que perderia a associação.

Exemplo — arquivar registros antes de uma migração destrutiva:

```ts src/logic-functions/pre-install.ts
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
import { createClient } from './generated/client';

const handler = async ({ previousVersion, newVersion }: InstallPayload): Promise<void> => {
  // Only the 1.x → 2.x upgrade drops the legacy `notes` field.
  if (!previousVersion?.startsWith('1.') || !newVersion.startsWith('2.')) {
    return;
  }

  const client = createClient();
  const legacyRecords = await client.postCard.findMany({
    where: { notes: { isNotNull: true } },
  });

  if (legacyRecords.length === 0) return;

  // Copy legacy `notes` into the new `description` field before the migration
  // drops the `notes` column. If this fails, the upgrade is aborted and the
  // workspace stays on v1 with all data intact.
  await Promise.all(
    legacyRecords.map((record) =>
      client.postCard.update({
        where: { id: record.id },
        data: { description: record.notes },
      }),
    ),
  );
};

export default definePreInstallLogicFunction({
  universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
  name: 'pre-install',
  description: 'Backs up legacy notes into description before the v2 migration.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: true,
  handler,
});
```

**Regra geral:**

| Você quer...                                                                                                        | Usar                                                                                      |
| ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Popular dados padrão, configurar o workspace, registrar recursos externos                                           | `post-install`                                                                            |
| Executar processos longos de popular dados ou chamadas a terceiros que não devem bloquear a resposta da instalação  | `post-install` (padrão — `shouldRunSynchronously: false`, com novas tentativas do worker) |
| Executar uma configuração rápida da qual o chamador dependerá imediatamente após o retorno da chamada de instalação | `post-install` com `shouldRunSynchronously: true`                                         |
| Ler ou fazer backup de dados que a próxima migração perderia                                                        | `pre-install`                                                                             |
| Rejeitar uma atualização que corromperia dados existentes                                                           | `pre-install` (lançar uma exceção no manipulador)                                         |
| Executar reconciliação em cada atualização                                                                          | `post-install` com `shouldRunOnVersionUpgrade: true`                                      |
| Fazer uma configuração única apenas na primeira instalação                                                          | `post-install` com `shouldRunOnVersionUpgrade: false` (padrão)                            |

<Note>
Em caso de dúvida, use **post-install** como padrão. Recurra à pré-instalação somente quando a própria migração for destrutiva e você precisar interceptar o estado anterior antes que ele desapareça.
</Note>

</Accordion>
</AccordionGroup>

## Clientes de API tipados (twenty-client-sdk)

O pacote `twenty-client-sdk` fornece dois clientes GraphQL tipados para interagir com a API do Twenty a partir das suas funções de lógica e componentes de front-end.

| Cliente             | Importar                     | Endpoint                                                             | Gerado?                    |
| ------------------- | ---------------------------- | -------------------------------------------------------------------- | -------------------------- |
| `CoreApiClient`     | `twenty-client-sdk/core`     | `/graphql` — dados do espaço de trabalho (registros, objetos)        | Sim, em tempo de dev/build |
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — configuração do espaço de trabalho, upload de arquivos | Não, vem pré-compilado     |

<AccordionGroup>
<Accordion title="CoreApiClient" description="Consultar e modificar dados do espaço de trabalho (registros, objetos)">

`CoreApiClient` é o cliente principal para consultar e mutar dados do espaço de trabalho. Ele é **gerado a partir do schema do seu espaço de trabalho** durante `yarn twenty dev` ou `yarn twenty build`, então é totalmente tipado para corresponder aos seus objetos e campos.

```ts
import { CoreApiClient } from 'twenty-client-sdk/core';

const client = new CoreApiClient();

// Query records
const { companies } = await client.query({
  companies: {
    edges: {
      node: {
        id: true,
        name: true,
        domainName: {
          primaryLinkLabel: true,
          primaryLinkUrl: true,
        },
      },
    },
  },
});

// Create a record
const { createCompany } = await client.mutation({
  createCompany: {
    __args: {
      data: {
        name: 'Acme Corp',
      },
    },
    id: true,
    name: true,
  },
});
```

O cliente usa uma sintaxe de selection-set: passe `true` para incluir um campo, use `__args` para argumentos e aninhe objetos para relações. Você tem preenchimento automático e verificação de tipos completos com base no schema do seu espaço de trabalho.

<Note>
**CoreApiClient é gerado em tempo de dev/build.** Se você usá-lo sem executar primeiro `yarn twenty dev` ou `yarn twenty build`, ele lançará um erro. A geração ocorre automaticamente — a CLI analisa o schema GraphQL do seu espaço de trabalho e gera um cliente tipado usando `@genql/cli`.
</Note>

#### Usando CoreSchema para anotações de tipo

`CoreSchema` fornece tipos TypeScript que correspondem aos objetos do seu espaço de trabalho — útil para tipar o estado de componentes ou parâmetros de função:

```ts
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
import { useState } from 'react';

const [company, setCompany] = useState<
  Pick<CoreSchema.Company, 'id' | 'name'> | undefined
>(undefined);

const client = new CoreApiClient();
const result = await client.query({
  company: {
    __args: { filter: { position: { eq: 1 } } },
    id: true,
    name: true,
  },
});
setCompany(result.company);
```

</Accordion>
<Accordion title="MetadataApiClient" description="Configuração do espaço de trabalho, aplicativos e upload de arquivos">

`MetadataApiClient` é fornecido pré-compilado com o SDK (não é necessário gerar). Ele consulta o endpoint `/metadata` para configuração do espaço de trabalho, aplicativos e upload de arquivos.

```ts
import { MetadataApiClient } from 'twenty-client-sdk/metadata';

const metadataClient = new MetadataApiClient();

// List first 10 objects in the workspace
const { objects } = await metadataClient.query({
  objects: {
    edges: {
      node: {
        id: true,
        nameSingular: true,
        namePlural: true,
        labelSingular: true,
        isCustom: true,
      },
    },
    __args: {
      filter: {},
      paging: { first: 10 },
    },
  },
});
```

#### Carregamento de arquivos

`MetadataApiClient` inclui um método `uploadFile` para anexar arquivos a campos do tipo arquivo:

```ts
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
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
  '58a0a314-d7ea-4865-9850-7fb84e72f30b',            // field universalIdentifier
);

console.log(uploadedFile);
// { id: '...', path: '...', size: 12345, createdAt: '...', url: 'https://...' }
```

| 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 (padrão para `application/octet-stream` se omitido)     |
| `fieldMetadataUniversalIdentifier` | `string` | O `universalIdentifier` do campo do tipo de arquivo no seu objeto |

Pontos-chave:
* 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.
* A `url` retornada é uma URL assinada que você pode usar para acessar o arquivo enviado.

</Accordion>
</AccordionGroup>

<Note>
  Quando seu código é executado no Twenty (funções de lógica ou componentes de front-end), a plataforma injeta credenciais como variáveis de ambiente:

  * `TWENTY_API_URL` — URL base da API do Twenty
  * `TWENTY_APP_ACCESS_TOKEN` — Chave de curta duração com escopo para o papel de função padrão do seu aplicativo

  Você **não** precisa passá-las para os clientes — eles leem de `process.env` automaticamente. As permissões da chave de API são determinadas pelo papel referenciado em `defaultRoleUniversalIdentifier` no seu `application-config.ts`.
</Note>
