Não existem SDKs oficiais da Vendaze. A API segue padrões REST e HTTP convencionais e funciona com qualquer cliente HTTP. Os snippets abaixo cobrem as operações mais comuns em três linguagens. Copie, adapte e use.Documentation Index
Fetch the complete documentation index at: https://developers.vendaze.com/llms.txt
Use this file to discover all available pages before exploring further.
Todos os exemplos assumem que você já completou o fluxo OAuth e tem um
access_token e
refresh_token válidos. Veja Autenticação se ainda não fez isso.Node.js
Usa a APIfetch nativa (Node.js 18+). Sem dependências externas.
- Troca de token OAuth
- Renovar access token
- Listar pessoas (paginado)
- Criar uma pessoa
- Cliente com auto-refresh
// Trocar um authorization code por tokens
async function exchangeCode({ code, clientId, clientSecret }) {
const res = await fetch('https://api.vendaze.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: clientId,
client_secret: clientSecret,
}),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
return res.json();
// { access_token, refresh_token, token_type, expires_in, workspace_slug }
}
// Renovar um access token expirado
async function refreshToken({ refreshToken, clientId, clientSecret }) {
const res = await fetch('https://api.vendaze.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: clientId,
client_secret: clientSecret,
}),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
return res.json();
}
// Buscar todas as pessoas de um workspace, tratando paginação automaticamente
async function listAllPeople(accessToken) {
const results = [];
let page = 1;
while (true) {
const res = await fetch(
`https://api.vendaze.com/v1/people?page=${page}&per_page=100&order_by=created_at&order=desc`,
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
const { data, meta } = await res.json();
results.push(...data);
if (!meta.has_more) break;
page++;
}
return results;
}
// Criar um novo contato no workspace
async function createPerson(accessToken, payload) {
const res = await fetch('https://api.vendaze.com/v1/people', {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify(payload),
});
if (!res.ok) {
const { error } = await res.json();
if (error.code === 'validation_error') {
console.error('Validação falhou:', error.fields);
}
throw new Error(`${error.code}: ${error.message}`);
}
const { data } = await res.json();
return data;
}
// Uso
const person = await createPerson(accessToken, {
full_name: 'Ana Costa',
emails: [{ email: 'ana@empresa.com', type: 'work' }],
phones: [{ phone: '+5511999990001', type: 'mobile' }],
position: 'Head of Sales',
});
// Cliente reutilizável com renovação automática de token
class VendazeClient {
constructor({ accessToken, refreshToken, clientId, clientSecret, onTokenRefresh }) {
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.onTokenRefresh = onTokenRefresh; // callback para persistir novos tokens
}
async request(path, options = {}) {
const res = await fetch(`https://api.vendaze.com${path}`, {
...options,
headers: {
Authorization: `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
...options.headers,
},
});
if (res.status === 401) {
const { error } = await res.json();
if (error.code === 'token_expired') {
await this._refresh();
return this.request(path, options); // retentar uma vez
}
throw new Error(`${error.code}: ${error.message}`);
}
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
if (res.status === 204) return null;
return res.json();
}
async _refresh() {
const res = await fetch('https://api.vendaze.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: this.refreshToken,
client_id: this.clientId,
client_secret: this.clientSecret,
}),
});
if (!res.ok) throw new Error('Refresh token expirado. Usuário precisa re-autorizar.');
const tokens = await res.json();
this.accessToken = tokens.access_token;
this.refreshToken = tokens.refresh_token;
if (this.onTokenRefresh) {
await this.onTokenRefresh(tokens);
}
}
}
// Uso
const client = new VendazeClient({
accessToken: storedAccessToken,
refreshToken: storedRefreshToken,
clientId: process.env.VENDAZE_CLIENT_ID,
clientSecret: process.env.VENDAZE_CLIENT_SECRET,
onTokenRefresh: async (tokens) => {
await db.updateTokens(workspaceSlug, tokens);
},
});
const { data: people } = await client.request('/v1/people?per_page=50');
Python
Usa a bibliotecahttpx (async). Instale com pip install httpx.
- Troca de token OAuth
- Listar pessoas (paginado)
- Criar uma pessoa
- Cliente com auto-refresh
import httpx
async def exchange_code(code: str, client_id: str, client_secret: str) -> dict:
async with httpx.AsyncClient() as client:
res = await client.post(
"https://api.vendaze.com/oauth/token",
data={
"grant_type": "authorization_code",
"code": code,
"client_id": client_id,
"client_secret": client_secret,
},
)
res.raise_for_status()
return res.json()
# { "access_token": ..., "refresh_token": ..., "workspace_slug": ... }
import httpx
async def list_all_people(access_token: str) -> list[dict]:
results = []
page = 1
headers = {"Authorization": f"Bearer {access_token}"}
async with httpx.AsyncClient() as client:
while True:
res = await client.get(
"https://api.vendaze.com/v1/people",
params={"page": page, "per_page": 100, "order_by": "created_at", "order": "desc"},
headers=headers,
)
res.raise_for_status()
body = res.json()
results.extend(body["data"])
if not body["meta"]["has_more"]:
break
page += 1
return results
import httpx
import uuid
async def create_person(access_token: str, payload: dict) -> dict:
async with httpx.AsyncClient() as client:
res = await client.post(
"https://api.vendaze.com/v1/people",
json=payload,
headers={
"Authorization": f"Bearer {access_token}",
"Idempotency-Key": str(uuid.uuid4()),
},
)
if res.status_code == 422:
error = res.json()["error"]
raise ValueError(f"Validação falhou: {error['fields']}")
res.raise_for_status()
return res.json()["data"]
# Uso
person = await create_person(access_token, {
"full_name": "Ana Costa",
"emails": [{"email": "ana@empresa.com", "type": "work"}],
"phones": [{"phone": "+5511999990001", "type": "mobile"}],
"position": "Head of Sales",
})
import httpx
import uuid
from typing import Callable, Awaitable
class VendazeClient:
def __init__(
self,
access_token: str,
refresh_token: str,
client_id: str,
client_secret: str,
on_token_refresh: Callable[[dict], Awaitable[None]] | None = None,
):
self.access_token = access_token
self.refresh_token = refresh_token
self.client_id = client_id
self.client_secret = client_secret
self.on_token_refresh = on_token_refresh
async def request(self, method: str, path: str, **kwargs) -> dict | None:
async with httpx.AsyncClient() as client:
res = await client.request(
method,
f"https://api.vendaze.com{path}",
headers={"Authorization": f"Bearer {self.access_token}"},
**kwargs,
)
if res.status_code == 401:
error = res.json()["error"]
if error["code"] == "token_expired":
await self._refresh()
return await self.request(method, path, **kwargs)
raise PermissionError(f"{error['code']}: {error['message']}")
if res.status_code == 204:
return None
res.raise_for_status()
return res.json()
async def _refresh(self):
async with httpx.AsyncClient() as client:
res = await client.post(
"https://api.vendaze.com/oauth/token",
data={
"grant_type": "refresh_token",
"refresh_token": self.refresh_token,
"client_id": self.client_id,
"client_secret": self.client_secret,
},
)
if not res.is_success:
raise PermissionError("Refresh token expirado. Usuário precisa re-autorizar.")
tokens = res.json()
self.access_token = tokens["access_token"]
self.refresh_token = tokens["refresh_token"]
if self.on_token_refresh:
await self.on_token_refresh(tokens)
Go
Usa apenas a biblioteca padrão. Sem dependências externas.- Troca de token OAuth
- Listar pessoas (paginado)
- Criar uma pessoa
package vendaze
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
type TokenResponse struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
WorkspaceSlug string `json:"workspace_slug"`
}
func ExchangeCode(code, clientID, clientSecret string) (*TokenResponse, error) {
form := url.Values{
"grant_type": {"authorization_code"},
"code": {code},
"client_id": {clientID},
"client_secret": {clientSecret},
}
res, err := http.Post(
"https://api.vendaze.com/oauth/token",
"application/x-www-form-urlencoded",
strings.NewReader(form.Encode()),
)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
var errBody struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
json.NewDecoder(res.Body).Decode(&errBody)
return nil, fmt.Errorf("%s: %s", errBody.Error.Code, errBody.Error.Message)
}
var tokens TokenResponse
if err := json.NewDecoder(res.Body).Decode(&tokens); err != nil {
return nil, err
}
return &tokens, nil
}
package vendaze
import (
"encoding/json"
"fmt"
"net/http"
)
type Person struct {
ID string `json:"id"`
FullName string `json:"full_name"`
CreatedAt string `json:"created_at"`
}
type PaginationMeta struct {
Total int `json:"total"`
Page int `json:"page"`
PerPage int `json:"per_page"`
HasMore bool `json:"has_more"`
}
func ListAllPeople(accessToken string) ([]Person, error) {
var results []Person
page := 1
client := &http.Client{}
for {
req, _ := http.NewRequest("GET",
fmt.Sprintf("https://api.vendaze.com/v1/people?page=%d&per_page=100", page),
nil,
)
req.Header.Set("Authorization", "Bearer "+accessToken)
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status inesperado: %d", res.StatusCode)
}
var body struct {
Data []Person `json:"data"`
Meta PaginationMeta `json:"meta"`
}
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
return nil, err
}
results = append(results, body.Data...)
if !body.Meta.HasMore {
break
}
page++
}
return results, nil
}
package vendaze
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"github.com/google/uuid"
)
type CreatePersonRequest struct {
FullName string `json:"full_name"`
Emails []ContactEmail `json:"emails,omitempty"`
Phones []ContactPhone `json:"phones,omitempty"`
Position string `json:"position,omitempty"`
}
type ContactEmail struct {
Email string `json:"email"`
Type string `json:"type,omitempty"`
}
type ContactPhone struct {
Phone string `json:"phone"`
Type string `json:"type,omitempty"`
}
func CreatePerson(accessToken string, payload CreatePersonRequest) (*Person, error) {
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.vendaze.com/v1/people", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.New().String())
res, err := (&http.Client{}).Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
var errBody struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
Fields map[string]string `json:"fields,omitempty"`
} `json:"error"`
}
json.NewDecoder(res.Body).Decode(&errBody)
return nil, fmt.Errorf("%s: %s", errBody.Error.Code, errBody.Error.Message)
}
var result struct {
Data Person `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
return nil, err
}
return &result.Data, nil
}