Get started

New customer setup

Sandbox-first repository integration, from SDK install and human-approved key bootstrap to a verified webhook boundary and deliberate production promotion.

Agents can bootstrap a first API key with the device authorization flow. A dashboard owner/admin still approves the request and selects the project/environment; public /v1/* calls continue to use API keys, not OAuth access tokens.

Six-minute platform tour

Watch the dashboard tour →

Tour pela Tyxter em 6 minutos (Veja antes do seu onboarding) · 6:19 · audio in Portuguese

This recording is a dashboard and product orientation. It does not replace the terminal-first path below: an integrating agent should still discover Tyxter through /llms.txt, /openapi.json, the docs MCP, SDK, and skills.

The chapter guide is the curated English accessibility and agent-readable companion. YouTube's automatic Portuguese captions are helpful, but they are not the canonical product copy.

Chapter guide

  1. 0:00Set expectations
    Explains that this is an orientation before onboarding and frames Tyxter as infrastructure that connects customer-owned agents to Meta and other providers.

  2. 1:12Operate messages and media
    Tours the dashboard views for sent and received messages, contacts, events, logs, webhooks, and media used by an agent.

  3. 1:57Prepare outbound journeys
    Introduces templates, Meta synchronization, WhatsApp Flows, audiences, and broadcasts, including the value of collecting structured data with fewer message turns.

  4. 2:47Configure agents and automations
    Shows dashboard configuration for AI agents, providers, models, credentials, and automations. It is a product tour, not a terminal implementation.

  5. 3:37Hand work to an integrating agent
    Briefly recommends giving Tyxter documentation and an environment-scoped API key to a coding agent, and distinguishes sandbox from production.

  6. 4:06Provision phones and connect providers
    Covers choosing a Brazilian area code, provisioning a Tyxter number or bringing an existing number, then connecting Meta and other provider integrations.

  7. 4:49Connect payments and MCP tools
    Introduces payment-provider connections, customer payment links, agentic payment tools, and the dashboard views used to inspect those operations.

  8. 5:34Explore safely and get help
    Closes with usage visibility, sandbox simulation, documentation, and support access from the dashboard top bar.

Resumo em português
  1. 0:00Alinhe as expectativas
    Explica que este é um panorama antes do onboarding e apresenta a Tyxter como a infraestrutura que conecta agentes do cliente à Meta e a outros provedores.

  2. 1:12Opere mensagens e mídias
    Percorre as telas do dashboard para mensagens enviadas e recebidas, contatos, eventos, logs, webhooks e mídias usadas por um agente.

  3. 1:57Prepare jornadas ativas
    Apresenta templates, sincronização com a Meta, WhatsApp Flows, audiências e disparos, incluindo o ganho de coletar dados estruturados com menos mensagens.

  4. 2:47Configure agentes e automações
    Mostra a configuração no dashboard de AI Agents, provedores, modelos, credenciais e automações. É um tour de produto, não uma implementação no terminal.

  5. 3:37Passe o trabalho para um agente integrador
    Recomenda brevemente entregar a documentação da Tyxter e uma chave de API por ambiente a um agente de código, distinguindo sandbox de produção.

  6. 4:06Provisione números e conecte provedores
    Cobre a escolha do DDD, o provisionamento de um número pela Tyxter ou a conexão de um número existente, seguida da conexão com a Meta e outros provedores.

  7. 4:49Conecte pagamentos e ferramentas MCP
    Apresenta conexões com provedores de pagamento, links de cobrança, ferramentas de pagamentos agentic e as telas para acompanhar essas operações.

  8. 5:34Explore com segurança e peça ajuda
    Encerra com visibilidade de uso, simulação no sandbox, documentação e acesso ao suporte pelo topo do dashboard.

1. Install the official SDK

Work in the application package that will own messaging. Detect its package manager from the repository's packageManager field or lockfile and run only the matching command. Do not create a second lockfile.

pnpm add @tyxter/sdk-js
npm install @tyxter/sdk-js
yarn add @tyxter/sdk-js
bun add @tyxter/sdk-js

Store real credentials in the repository's existing ignored env convention. Commit only blank TYXTER_API_KEY=, TYXTER_TEST_RECIPIENT=, and TYXTER_WEBHOOK_SECRET= placeholders to an example env file.

2. Bootstrap a sandbox key

POST/v1/agent-api-key-device-authorizations201 Created
import { TyxterApiError, TyxterBootstrap } from '@tyxter/sdk-js';

const bootstrap = new TyxterBootstrap();
const authorization = await bootstrap.agentApiKeyDeviceAuthorizations.create({
  client_name: 'Messaging integration for <repository-name>',
  environment: 'sandbox',
  scopes: [
    'sandbox:write',
    'messages:send',
    'messages:read',
    'webhooks:write',
    'webhooks:read',
  ],
});
console.info(authorization.verification_uri_complete);

const deadline = Date.now() + authorization.expires_in * 1_000;
let intervalSeconds = authorization.interval;
let approvedSecret: string | undefined;
while (Date.now() < deadline) {
  await new Promise((resolve) => setTimeout(resolve, intervalSeconds * 1_000));
  try {
    const token = await bootstrap.agentApiKeyDeviceAuthorizations.token({
      grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
      device_code: authorization.device_code,
    });
    if (token.status === 'pending') {
      intervalSeconds = Math.max(intervalSeconds, token.interval);
      continue;
    }
    approvedSecret = token.api_key.secret;
    break;
  } catch (error) {
    if (
      error instanceof TyxterApiError &&
      (error.code === 'device_code_expired' || error.code === 'authorization_denied')
    ) {
      throw new Error(`Tyxter device authorization stopped: ${error.code}`);
    }
    throw error;
  }
}
if (!approvedSecret || !approvedSecret.startsWith('tx_sandbox_')) {
  throw new Error('A tx_sandbox_ key is required');
}

Send the human to verification_uri_complete. The dashboard approval page requires an owner/admin session and a sandbox environment. The first integration must not request production.

POST/v1/agent-api-key-device-authorizations/token

The SDK returns HTTP 202 as the typed pending result and the loop never polls faster than the latest interval. After approval, HTTP 200 returns a one-time kind=agent API key plus preflight checks. The key must start with tx_sandbox_; otherwise stop and start a new sandbox authorization. The same flow is exposed by the SDK's unauthenticated TyxterBootstrap client.

Dashboard fallback

  1. Owner/admin signs in at https://tyxter.com/login.
  2. Owner/admin creates an agent-scoped API key for the selected sandbox environment.
  3. Owner/admin completes setup that requires elevated scopes, such as Meta connection, phone-number provisioning, billing, and payment-provider setup.
  4. The agent receives the API key as a secret and runs the sandbox proof below before any production work.

Before choosing a number source, read WABA and phone-number ownership. A customer-owned Meta account, a BYON number, and a Tyxter-managed Salvy rental have different exit paths.

Agent key limits

Agent-scoped keys cannot be granted api_keys:admin, billing:write, payments:write, agentic_payments:write, phone_numbers:write, or provider_connections:write. Use a standard dashboard-created key when a setup workflow must call provider or phone-number write APIs.

3. Prove the first sandbox send

GET/v1/sandbox/quickstart

Require a non-null sender.default_sender_id and capabilities.send_outbound_messages === true. Stop on returned missing scopes or sender setup instead of inventing an id. Open the sandbox service window, then send with the same test recipient:

POST/v1/sandbox/inbound-messages
POST/v1/messages
import { randomUUID } from 'node:crypto';
import { Tyxter } from '@tyxter/sdk-js';

const apiKey = process.env.TYXTER_API_KEY!;
if (!apiKey.startsWith('tx_sandbox_')) throw new Error('Sandbox key required');
const tyxter = new Tyxter({ apiKey });
const ready = await tyxter.sandbox.quickstart();
const sender = ready.sender.default_sender_id;
if (!sender || !ready.capabilities.send_outbound_messages) {
  throw new Error('Sandbox sender is not ready');
}

const recipient = process.env.TYXTER_TEST_RECIPIENT!;
if (!/^\+[1-9]\d{7,14}$/.test(recipient)) throw new Error('E.164 recipient required');
await tyxter.sandbox.inboundMessages.create(
  {
    channel: 'whatsapp',
    from: recipient,
    to: sender,
    type: 'text',
    text: { body: 'Opening the Tyxter sandbox service window.' },
  },
  { idempotencyKey: randomUUID() },
);
const message = await tyxter.whatsapp.sendText(
  { from: sender, to: recipient, body: 'Tyxter sandbox integration check.' },
  { idempotencyKey: randomUUID() },
);
if (message.status !== 'accepted') throw new Error(`Unexpected status: ${message.status}`);
const detail = await tyxter.messages.retrieve(message.id);
console.info({ message_id: message.id, trace_id: message.trace_id, status: detail.status });

Generate one idempotency key per logical write and reuse it for retries of that same write. A successful proof is an accepted message produced by a tx_sandbox_ key; it does not require Meta credentials or billing.

4. Add and verify the webhook receiver

Add a route in the repository's existing server framework and preserve the exact raw body before JSON parsing. Read the three Tyxter headers case-insensitively and verify before parsing:

import { verifyWebhookSignature } from '@tyxter/sdk-js/webhook-verifier';

const valid = verifyWebhookSignature({
  secret: process.env.TYXTER_WEBHOOK_SECRET!,
  timestamp: tyxterWebhookTimestamp,
  signature: tyxterWebhookSignature,
  rawBody,
});

Reject missing or invalid signatures before parsing. Deduplicate by tyxter-webhook-id with a durable unique insert, then persist or enqueue and acknowledge quickly. Do not silently use process memory. Never verify re-serialized JSON or hand-roll HMAC logic.

POST/v1/webhook-endpoints
const endpoint = await tyxter.webhookEndpoints.create(
  {
    url: approvedPublicHttpsUrl,
    description: 'Sandbox integration receiver',
    subscribed_events: ['message.received'],
  },
  { idempotencyKey: randomUUID() },
);
// Store endpoint.signing_secret as TYXTER_WEBHOOK_SECRET; it is returned once.

Trigger another sandbox inbound message. Capture the genuine raw body and headers only in memory for the diagnostic run: the original must return 2xx, and a one-byte body change with the same headers must return 401. If no public HTTPS URL is approved, leave registration explicitly pending instead of inventing a tunnel.

5. Keep the public contract explicit

6. Promote to production separately

Do not replace the sandbox key during the first-send task. Production requires a new, explicit human approval and a distinct tx_live_ key.

Start a new device authorization with environment: "production". Before switching a production deployment, run the following preflight and stop if any resource is not the one the human intended:

GET/v1/account
GET/v1/provider-connections/status
GET/v1/phone-numbers
GET/v1/templates

Confirm the organization/environment, ready WhatsApp connection, active sender, and any approved template the application needs. Register a production webhook with the production key and keep its signing secret separate. Preserve the sandbox configuration for deterministic tests.