Registro de atividade
Leia o registro da sua organização com as chamadas de API e os eventos de arquivos e registros.
Visão geral
O Registro de atividade é o registro da própria organização sobre o que aconteceu na Inovacc: toda chamada de API e todo evento de arquivo e de registro que essas chamadas causaram. Você o lê com um único endpoint, GET /v1/activity em https://data.inovacc.dev, filtrado por período, tipo de evento ou hash de arquivo.
O problema que ele resolve é responder "quem fez o quê, e quando" sem construir a sua própria trilha de auditoria. O registro é mantido pela Inovacc para toda chamada às APIs de Dados, de IA e de Eventos, quer a sua aplicação se lembre ou não de gravar alguma coisa. Registrar é um fato do serviço, não uma opção, e uma organização só enxerga os próprios registros.
Use-o para auditorias, para investigar uma integração que falhou ("quais chamadas foram recusadas esta manhã, e com qual código?"), para provar que um arquivo foi entregue (o evento de download carrega o SHA-256 do arquivo) e para ter uma visão do tráfego por chave. Para ver quanto o seu uso de IA custou, use o resumo de uso do Chat com IA (GET /v1/usage/summary): o Registro de atividade registra eventos, nunca preços.
Conceitos
Eventos e tipos. Cada registro é um evento com um kind:
| Tipo | Gravado quando |
|---|---|
api.call | qualquer chamada autenticada, inclusive as recusadas (403, 429) |
record.write, record.delete | um registro é criado, alterado ou excluído (um por operação de um lote) |
blob.write, blob.read, blob.delete | um blob de banco de dados é enviado, baixado ou excluído |
file.upload.completed, file.download, file.delete | um arquivo é gravado, baixado ou excluído |
file.upload.started, file.processed | gravados por outros serviços da Inovacc, como envios e conversões de IA |
O que um registro contém. O horário (at_ms, milissegundos Unix), a organização, quem agiu (actor_kind: user, key ou service, e actor_id), o serviço de origem source, o method, a route (um modelo como /v1/databases/{database}/collections/{collection}/records/{record_id}, nunca os ids em si), o status, o outcome, o error_code de uma falha, a latência, os tamanhos de entrada e saída e, para um arquivo, seu tamanho, tipo e SHA-256. related aponta para o banco de dados, a coleção e o registro, ou para o envio ou trabalho, envolvidos. Todas as chaves estão sempre presentes, null quando não se aplicam.
O que ele nunca contém. Um prompt, o corpo de uma resposta ou o conteúdo de um arquivo. As chamadas de IA nunca registram o nome de um arquivo.
País. Um registro api.call traz country: o país de quem chamou, como a borda de rede da Inovacc o vê (duas letras, XX quando desconhecido). Ele não pode ser definido por quem chama, e o registro não guarda cidade, endereço IP nem coordenadas.
Retenção. Os registros são mantidos por um ano. Os últimos 30 dias respondem imediatamente; os registros mais antigos vêm do arquivo morto e demoram mais.
Como funciona
Chame GET /v1/activity com Authorization: Bearer <credential>. A credencial precisa da permissão de leitura de atividade no nível da organização; uma credencial limitada a registros não a tem. A organização é sempre a da credencial: não há parâmetro que nomeie outra.
Todo parâmetro é opcional:
| Parâmetro | Significado |
|---|---|
from, to | milissegundos Unix, UTC; from inclusivo, to exclusivo |
kind | um ou mais tipos, separados por vírgula |
file_sha256 | 64 caracteres hexadecimais minúsculos: todos os eventos desse arquivo |
limit | de 1 a 500, padrão 100 |
cursor | o next_cursor da página anterior, sem alteração |
Qualquer outro parâmetro, um repetido ou vazio, ou um valor inválido resulta em 400 invalid_query, e nada é lido. A resposta vem do mais novo para o mais antigo: {"items":[...],"next_cursor":<string|null>,"archive_searched":<bool>}. Siga next_cursor até que seja null. archive_searched informa que a leitura foi além dos últimos 30 dias. Uma leitura pode voltar no máximo 366 dias por chamada.
Os registros aparecem alguns segundos depois da chamada, não instantaneamente. O registro acontece depois da resposta e nunca a altera: se o registro não puder ser gravado, a chamada é respondida normalmente. Um download de Dados ou de Arquivos é registrado quando começa; um download da API de IA é registrado quando a transferência termina. A API de IA também oferece GET /v1/activity em https://ai.inovacc.dev para as suas próprias chamadas, com from e to como instantes RFC 3339; lê-lo ali não é cobrado.
Primeiros passos
Você precisa de uma credencial com a permissão de leitura de atividade (Autenticação).
- Faça uma chamada para ser registrada. Grave um registro em Dados ou envie um arquivo em Arquivos.
- Leia os eventos mais recentes.
GET /v1/activity?limit=10(veja os exemplos). A sua chamada está lá comoapi.call, com o modelo de rota e o status, seguida do seurecord.writeoufile.upload.completed. - Filtre por tipo.
GET /v1/activity?kind=api.call&limit=50mostra apenas chamadas; observestatuseerror_codepara encontrar recusas. - Acompanhe um arquivo. Pegue o
file_sha256do seu envio e chameGET /v1/activity?file_sha256=<hash>: todo envio, download e exclusão desse conteúdo é listado. - Pagine. Devolva o
next_cursorcomocursoraté que sejanull.
Casos de uso
Uma resposta de auditoria. Um cliente pergunta quem excluiu um registro na terça-feira passada. Filtre kind=record.delete com from e to em torno desse dia; o evento nomeia o autor e related nomeia o banco de dados, a coleção e o registro.
Prova de entrega. Uma equipe de conformidade precisa mostrar que um relatório chegou a um parceiro. O evento file.download traz o SHA-256 e o tamanho dos bytes enviados, e o horário, que podem ser comparados com o arquivo original.
Saúde de uma integração. Uma integração começa a falhar à noite. Filtrar kind=api.call para essa janela mostra o status e o error_code de cada chamada feita pela chave da integração, por exemplo uma sequência de 429 rate_limited que aponta para a falta de espera crescente.
Limites e preços
| Limite | Valor |
|---|---|
| Retenção | um ano; os últimos 30 dias respondem imediatamente |
| Intervalo de uma leitura | 366 dias |
| Tamanho da página | 1 a 500 (padrão 100) |
| Atraso até um evento ficar legível | alguns segundos |
| Taxa | 600 requisições por minuto por titular de credencial, por localização |
Preços: sob consulta.
Erros
| Status | Código | O que significa e o que fazer |
|---|---|---|
| 400 | invalid_query | Um parâmetro é desconhecido, repetido, vazio ou inválido; corrija a consulta. |
| 401 | invalid_credentials | Envie uma credencial válida. |
| 403 | forbidden | A credencial não tem a permissão de leitura de atividade. |
| 429 | rate_limited | Diminua o ritmo. |
| 503 | service_unavailable | O registro não pode ser lido agora; tente novamente mais tarde. |
Boas práticas
- Filtre no servidor: passe
kind,frometoem vez de ler tudo e filtrar no seu código. - Guarde o
at_msmais recente que você processou e leia a partir dele na próxima execução, seguindo os cursores até o fim. - Use
file_sha256para rastrear um arquivo entre envios, downloads e processamento de IA. - Espere alguns segundos de atraso; não trate um evento recém-criado que ainda não aparece como uma falha.
- Ignore chaves que você não conhece: os registros podem ganhar campos.
- Dê a cada integração a sua própria chave, para que
actor_iddiga qual delas agiu.
Relacionados
- Dados, Arquivos, Eventos
- Chat com IA: uso e custo por chave e rota
- Autenticação, Erros, Limites
Autenticação
Toda chamada leva a sua chave; a sua organização vem dela. Veja o guia de autenticação.
AuthorizationEndpoints
GET /v1/activity
Exemplo
Linguagem
⋮
cURL
curl "https://data.inovacc.dev/v1/activity" \
-H "Authorization: Bearer $INOVACC_API_KEY"curl "https://data.inovacc.dev/v1/activity" \
-H "Authorization: Bearer $INOVACC_API_KEY"
TypeScript
const url = "https://data.inovacc.dev/v1/activity";
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
},
});
console.log(response.status, await response.text());const url = "https://data.inovacc.dev/v1/activity";
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
},
});
console.log(response.status, await response.text());
Python
import os
import urllib.request
request = urllib.request.Request(
"https://data.inovacc.dev/v1/activity",
method="GET",
headers={
"User-Agent": "inovacc-python-sample",
"Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
},
)
with urllib.request.urlopen(request) as response:
print(response.status, response.read().decode())import os
import urllib.request
request = urllib.request.Request(
"https://data.inovacc.dev/v1/activity",
method="GET",
headers={
"User-Agent": "inovacc-python-sample",
"Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
},
)
with urllib.request.urlopen(request) as response:
print(response.status, response.read().decode())
Go
package main
import (
"fmt"
"io"
"net/http"
"os"
)
const url = "https://data.inovacc.dev/v1/activity"
func main() {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(res.Status, string(out))
}package main
import (
"fmt"
"io"
"net/http"
"os"
)
const url = "https://data.inovacc.dev/v1/activity"
func main() {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(res.Status, string(out))
}
Rust
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("INOVACC_API_KEY")?;
let response = reqwest::blocking::Client::new()
.get("https://data.inovacc.dev/v1/activity")
.bearer_auth(api_key)
.send()?;
println!("{} {}", response.status(), response.text()?);
Ok(())
}// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("INOVACC_API_KEY")?;
let response = reqwest::blocking::Client::new()
.get("https://data.inovacc.dev/v1/activity")
.bearer_auth(api_key)
.send()?;
println!("{} {}", response.status(), response.text()?);
Ok(())
}
JavaScript
const url = "https://data.inovacc.dev/v1/activity";
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
},
});
console.log(response.status, await response.text());const url = "https://data.inovacc.dev/v1/activity";
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
},
});
console.log(response.status, await response.text());
PHP
<?php
$curl = curl_init('https://data.inovacc.dev/v1/activity');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
],
]);
$response = curl_exec($curl);
echo curl_getinfo($curl, CURLINFO_HTTP_CODE), ' ', $response, "\n";
curl_close($curl);<?php
$curl = curl_init('https://data.inovacc.dev/v1/activity');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
],
]);
$response = curl_exec($curl);
echo curl_getinfo($curl, CURLINFO_HTTP_CODE), ' ', $response, "\n";
curl_close($curl);
Ruby
require "net/http"
require "uri"
uri = URI('https://data.inovacc.dev/v1/activity')
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts "#{response.code} #{response.body}"require "net/http"
require "uri"
uri = URI('https://data.inovacc.dev/v1/activity')
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts "#{response.code} #{response.body}"
Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("INOVACC_API_KEY");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://data.inovacc.dev/v1/activity"))
.header("Authorization", "Bearer " + apiKey)
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("INOVACC_API_KEY");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://data.inovacc.dev/v1/activity"))
.header("Authorization", "Bearer " + apiKey)
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}
C#
var url = "https://data.inovacc.dev/v1/activity";
var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");var url = "https://data.inovacc.dev/v1/activity";
var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");
Kotlin
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
fun main() {
val apiKey = System.getenv("INOVACC_API_KEY")
val request = HttpRequest.newBuilder()
.uri(URI.create("https://data.inovacc.dev/v1/activity"))
.header("Authorization", "Bearer " + apiKey)
.GET()
.build()
val response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString())
println("${response.statusCode()} ${response.body()}")
}import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
fun main() {
val apiKey = System.getenv("INOVACC_API_KEY")
val request = HttpRequest.newBuilder()
.uri(URI.create("https://data.inovacc.dev/v1/activity"))
.header("Authorization", "Bearer " + apiKey)
.GET()
.build()
val response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString())
println("${response.statusCode()} ${response.body()}")
}
Swift
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
let apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""
let url = URL(string: "https://data.inovacc.dev/v1/activity")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
let status = (response as? HTTPURLResponse)?.statusCode ?? 0
print(status, String(decoding: data, as: UTF8.self))import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
let apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""
let url = URL(string: "https://data.inovacc.dev/v1/activity")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
let status = (response as? HTTPURLResponse)?.statusCode ?? 0
print(status, String(decoding: data, as: UTF8.self))
Detalhes da fonte
- Id
- identity/component-taxonomy/capabilities#activity
- Repositório
- identity
- Caminho
- contracts/component-taxonomy/catalog/capabilities.json
- Commit
- 08ef3cd75d82
- Id
- identity/component-taxonomy/quickstart#activity
- Repositório
- identity
- Caminho
- contracts/component-taxonomy/catalog/capabilities.json
- Commit
- 08ef3cd75d82