Aparência
Início rápido
Em quatro passos você sai do zero e lê dados reais da sua empresa: criar a credencial, pedir o token, conferir quem você é e consultar eventos. Tudo leva poucos minutos.
Antes de começar
Você precisa de uma empresa nos planos Premium ou Enterprise e de um usuário com a permissão Gerenciar a API pública e as chaves MCP. Os detalhes estão em Introdução.
1. Criar a credencial
- No Festero, abra API do Festero no menu lateral.
- Clique em Nova credencial.
- Dê um nome que ajude você a reconhecê-la depois (até 80 caracteres), por exemplo
Integração com o ERP. - Marque os conjuntos de dados que ela pode ler. Para este guia, marque Eventos.
- Clique em Criar credencial.
O Festero mostra então quatro valores. Copie todos:
| Valor | Para que serve |
|---|---|
client_id | Identifica a credencial. Não é secreto. |
client_secret | A senha da credencial. |
| Endpoint do token | https://auth.festero.com.br/oauth2/token |
Parâmetro scope | Os escopos da credencial no formato do pedido de token, por exemplo festero-api/events:read. |
Guarde o segredo agora
O client_secret aparece uma única vez. Depois de fechar a janela, não é possível vê-lo de novo. Se perder, crie outra credencial. Ao fechar, o Festero ainda pergunta se você copiou.
A credencial nasce com o status Ativando e pode levar alguns minutos para ficar Ativa. A lista na tela se atualiza sozinha. Faça os testes abaixo só depois que ela estiver ativa.
2. Pedir o token
A API usa o fluxo client credentials do OAuth 2.0: você troca o client_id e o client_secret por um token de acesso. O token vale por 60 minutos. No curl, $CLIENT_ID e $CLIENT_SECRET são variáveis do seu terminal com os valores da credencial, e nos passos seguintes $ACCESS_TOKEN é o access_token da resposta.
bash
curl -X POST https://auth.festero.com.br/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=festero-api/events:read"js
const basic = Buffer.from(`${process.env.FESTERO_CLIENT_ID}:${process.env.FESTERO_CLIENT_SECRET}`).toString('base64')
const resposta = await fetch('https://auth.festero.com.br/oauth2/token', {
method: 'POST',
headers: { Authorization: `Basic ${basic}`, 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ grant_type: 'client_credentials', scope: 'festero-api/events:read' }),
})
const { access_token, expires_in } = await resposta.json()python
import os
import requests
resposta = requests.post(
"https://auth.festero.com.br/oauth2/token",
auth=(os.environ["FESTERO_CLIENT_ID"], os.environ["FESTERO_CLIENT_SECRET"]),
data={"grant_type": "client_credentials", "scope": "festero-api/events:read"},
)
corpo = resposta.json()
access_token = corpo["access_token"]csharp
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var clientId = Environment.GetEnvironmentVariable("FESTERO_CLIENT_ID");
var clientSecret = Environment.GetEnvironmentVariable("FESTERO_CLIENT_SECRET");
using var http = new HttpClient();
var basic = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));
var pedido = new HttpRequestMessage(HttpMethod.Post, "https://auth.festero.com.br/oauth2/token")
{
Headers = { Authorization = new AuthenticationHeaderValue("Basic", basic) },
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["scope"] = "festero-api/events:read",
}),
};
var resposta = await http.SendAsync(pedido);
resposta.EnsureSuccessStatusCode();
using var corpo = JsonDocument.Parse(await resposta.Content.ReadAsStringAsync());
var accessToken = corpo.RootElement.GetProperty("access_token").GetString();A resposta traz o token e o tempo de validade, em segundos:
json
{
"access_token": "eyJraWQiOi...",
"expires_in": 3600,
"token_type": "Bearer"
}Para pedir mais de um conjunto de dados, separe os escopos por espaço: festero-api/events:read festero-api/quotes:read. Quando o espaço vai num corpo de formulário no curl, codifique-o como %20. Veja todos os escopos em Autenticação.
3. Conferir quem você é
GET /v1/me não exige escopo e devolve a credencial, a empresa e o plano. É a forma mais barata de testar o token.
bash
curl https://platform.festero.com.br/v1/me \
-H "Authorization: Bearer $ACCESS_TOKEN"js
const me = await fetch('https://platform.festero.com.br/v1/me', {
headers: { Authorization: `Bearer ${access_token}` },
})
console.log(await me.json())python
me = requests.get(
"https://platform.festero.com.br/v1/me",
headers={"Authorization": f"Bearer {access_token}"},
)
print(me.json())csharp
var pedidoMe = new HttpRequestMessage(HttpMethod.Get, "https://platform.festero.com.br/v1/me");
pedidoMe.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var me = await http.SendAsync(pedidoMe);
Console.WriteLine(await me.Content.ReadAsStringAsync());json
{
"credentialId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"workspaceId": "0f8fad5b-d9cb-469f-a165-70867728950e",
"scopes": ["events:read"],
"tier": "PREMIUM",
"authKind": "jwt"
}Se a resposta for 401 ou 403, veja o campo code em Erros. Logo depois de criar a credencial, credential_revoked costuma significar que ela ainda está Ativando.
4. Consultar eventos
Agora uma consulta de verdade. Os cinco eventos mais antigos por data de alteração:
bash
curl "https://platform.festero.com.br/v1/events?limit=5" \
-H "Authorization: Bearer $ACCESS_TOKEN"json
{
"data": [
{
"id": "b7e2c4a1-95d3-4f08-a6b2-1c8d3e5f7a90",
"title": "Casamento Camila e Rafael",
"status": "upcoming",
"kind": "conventional",
"eventType": { "id": "5d1a8c33-7e42-49b6-8f10-c2a9b4d6e871", "name": "Casamento" },
"client": { "id": "9a3e7d52-1b68-4c04-b7f9-e0d2a5c8316b", "name": "Camila Duarte" },
"eventDate": "2027-03-20",
"eventTime": "18:00",
"durationHours": 5,
"guestCount": 150,
"city": "Salvador",
"state": "BA",
"isRental": false,
"quoteId": "e4f6a9b2-3c71-4d85-9b0e-7a1c5d8f2634",
"totalAmount": { "amount": 42800.00, "currency": "BRL" },
"discount": { "amount": 1500.00, "currency": "BRL" },
"travelFee": null,
"contractedAt": "2026-10-10T20:15:31-03:00",
"createdAt": "2026-10-08T10:12:40-03:00",
"updatedAt": "2026-10-10T20:15:31-03:00"
}
],
"nextCursor": "eyJ0IjozOTU0..."
}A lista foi abreviada aqui: a resposta real traz até 5 itens em data. Quando nextCursor vem preenchido, há mais resultados: repita a chamada com cursor=<esse valor>. Veja Paginação e datas. Todos os campos de evento estão em Eventos.
Exemplo completo
O código abaixo guarda o token até perto de vencer, percorre todas as páginas e imprime os eventos de novembro de 2026. Troque events:read pelos escopos da sua credencial.
js
const TOKEN_URL = 'https://auth.festero.com.br/oauth2/token'
const API = 'https://platform.festero.com.br'
let token = null // { valor, venceEm }
async function obterToken() {
// Reaproveita o token até 1 minuto antes de vencer: pedir um por chamada é caro e limitado.
if (token && Date.now() < token.venceEm - 60_000) return token.valor
const basic = Buffer.from(`${process.env.FESTERO_CLIENT_ID}:${process.env.FESTERO_CLIENT_SECRET}`).toString('base64')
const resposta = await fetch(TOKEN_URL, {
method: 'POST',
headers: { Authorization: `Basic ${basic}`, 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ grant_type: 'client_credentials', scope: 'festero-api/events:read' }),
})
if (!resposta.ok) throw new Error(`Falha ao pedir o token: HTTP ${resposta.status}`)
const corpo = await resposta.json()
token = { valor: corpo.access_token, venceEm: Date.now() + corpo.expires_in * 1000 }
return token.valor
}
async function festero(caminho, parametros = {}) {
const url = new URL(caminho, API)
for (const [nome, valor] of Object.entries(parametros)) url.searchParams.set(nome, valor)
const resposta = await fetch(url, { headers: { Authorization: `Bearer ${await obterToken()}` } })
if (!resposta.ok) {
const problema = await resposta.json().catch(() => null)
throw new Error(`HTTP ${resposta.status} ${problema?.code ?? ''} (requestId ${problema?.requestId ?? 'n/d'})`)
}
return resposta.json()
}
let cursor
do {
const pagina = await festero('/v1/events', {
eventDateFrom: '2026-11-01',
eventDateTo: '2026-11-30',
limit: 100,
...(cursor && { cursor }),
})
for (const evento of pagina.data) console.log(evento.eventDate, evento.title, evento.status)
cursor = pagina.nextCursor
} while (cursor)Próximos passos
- Autenticação: escopos, validade da credencial, rotação e revogação.
- Limites de uso: quantas chamadas cada plano permite.
- Erros: o que cada
codesignifica e o que fazer. - Webhooks: receba avisos em vez de consultar de tempos em tempos.
- Referência interativa: teste qualquer rota no navegador.