Vai al contenuto
CloseYourItdocsPagine

Documentazione / Collega

API HTTP

Manda errori, log, metriche e visite con semplici richieste HTTP, senza un SDK.

Gli SDK sono una comodità: sotto, ognuno fa le richieste HTTP di questa pagina. Usa l'API direttamente da un linguaggio senza SDK, da uno script o dalla CI.

Prima di cominciare

Ti servono tre cose, tutte dalle impostazioni del progetto in CloseYourIt:

  • l'indirizzo della tua installazione, per esempio https://bugs.example.com;
  • l'id del progetto;
  • un token di ingest (cyi_…).

Il token è segreto e resta sul server. ingest permette di mandare dati; le letture private richiedono lo scope separato read. I client browser e mobile usano una chiave pubblica per i segnali supportati, senza accesso in lettura né di amministrazione. I segnali disponibili dipendono dall'SDK e dalla versione; vedi SDK JavaScript.

Ogni richiesta porta il token e manda JSON, con i nomi dei campi in snake_case:

Authorization: Bearer cyi_...
Content-Type: application/json

Dove mandare

CosaIndirizzoCorpoRisposta
ErrorePOST /api/v1/projects/<id>/eventsun evento202 {"data":{"id":"…"}}
PrestazioniPOST /api/v1/projects/<id>/metricsun campione o una lista202 {"data":{"accepted":N}}
LogPOST /api/v1/projects/<id>/logsuna riga o una lista202 {"data":{"accepted":N}}
VisitePOST /api/v1/projects/<id>/pageviewsuna visita o una lista202 {"data":{"accepted":N}}
Registrazione della sessionePOST /api/v1/projects/<id>/replaysun pezzo o una lista202 {"data":{"accepted":N}}

L'<id> nell'indirizzo deve essere il progetto a cui appartiene il token.

202 vuol dire accettato, non salvato: i dati li scrive un attimo dopo un lavoro in background. accepted conta gli elementi che hanno passato i primi controlli.

Mandare un errore

Il corpo è un evento nel formato di Sentry.

curl -X POST https://bugs.example.com/api/v1/projects/$PROJECT_ID/events \
  -H "Authorization: Bearer $CYI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "fc6d8c0c43fc4630ad850ee518f1b9d0",
    "timestamp": "2026-10-03T10:15:30Z",
    "level": "error",
    "platform": "ruby",
    "environment": "production",
    "release": "v1.4.2",
    "exception": { "values": [ {
      "type": "RuntimeError",
      "value": "boom",
      "stacktrace": { "frames": [
        { "filename": "app/models/order.rb", "function": "charge", "lineno": 42, "in_app": true }
      ] }
    } ] }
  }'
CampoNote
event_idun tuo id unico; mandare due volte lo stesso non crea un secondo errore
timestampISO 8601 o secondi dal 1970; di base è adesso
leveldebug, info, warning, error o fatal; di base error
exception.values[]ognuno con type, value e stacktrace.frames[]; si legge l'ultimo
messageusato come titolo quando manca exception
environment, release, server_name, platformfacoltativi
userid, email, ip_address: se ne tiene solo un hash
request, breadcrumbs, tags, extra, contextsfacoltativi; i valori sotto chiavi sensibili diventano [FILTERED]
trace_idcollega l'errore ai log della stessa richiesta
fingerprintuna lista che sostituisce il modo in cui gli errori si raggruppano

Gli errori si raggruppano per tipo di eccezione e punto del codice, non per il testo del messaggio.

Mandare log

curl -X POST https://bugs.example.com/api/v1/projects/$PROJECT_ID/logs \
  -H "Authorization: Bearer $CYI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    { "timestamp": "2026-10-03T10:15:30Z", "level": "info", "message": "order charged",
      "logger": "billing", "attributes": { "order_id": 7 } }
  ]'
CampoNote
messageobbligatorio, non vuoto. Si salva così come lo mandi: non metterci segreti
leveldebug, info, warning, error o fatal; qualsiasi altro valore diventa info
timestampISO 8601 o secondi dal 1970
loggeril nome della parte della tua app che l'ha scritto
attributesun oggetto qualsiasi; i valori sotto chiavi sensibili vengono filtrati
event_id, trace_id, environment, releasefacoltativi

Mandare campioni di prestazioni

curl -X POST https://bugs.example.com/api/v1/projects/$PROJECT_ID/metrics \
  -H "Authorization: Bearer $CYI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    { "kind": "slow_query", "duration_ms": 812.4,
      "sql": "SELECT * FROM orders WHERE id = 7", "environment": "production" },
    { "kind": "slow_method", "duration_ms": 240.0, "label": "Invoice#render" }
  ]'
CampoNote
kindobbligatorio: slow_query, slow_method o performance_issue
duration_msquanto è durato
sqlper slow_query; numeri e id vengono sostituiti, così le query uguali si raggruppano
labelper slow_method; obbligatorio, è ciò per cui si raggruppano i campioni
subtypeper performance_issue; obbligatorio: n_plus_one, slow_request, slow_external_http, high_query_count, jank, repeated_http o rebuild_storm
sample_idun tuo id unico (un UUID), per ritentare senza doppioni
occurred_at, environment, trace_idfacoltativi

Mandare visite

curl -X POST https://bugs.example.com/api/v1/projects/$PROJECT_ID/pageviews \
  -H "Authorization: Bearer $CYI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "hostname": "www.example.com", "path": "/pricing",
        "referrer": "https://www.google.com/", "utm_source": "newsletter" }'
CampoNote
hostname, pathobbligatori. path non contiene mai la query string
namelascialo fuori per una visita; qualsiasi altro nome è un evento personalizzato
referrerse ne tiene solo il nome dell'host
utm_source, utm_medium, utm_campaign, utm_term, utm_contentfacoltativi
screen_widthin pixel; si salva solo la classe (telefono, tablet, portatile, desktop)
event_id, occurred_at, environmentfacoltativi

Non si usano cookie. Il visitatore si conta da un hash che cambia ogni giorno e non si può riportare a una persona. Una richiesta che sembra di un bot riceve 202 con accepted: 0.

Le visite richiedono il token segreto, quindi questo indirizzo si chiama dal tuo server, non dal browser. Per un sito web usa l'SDK JavaScript.

Limiti

LimiteValore
Log in una richiesta1000
Campioni di prestazioni in una richiesta1000
Visite in una richiesta100
Pezzi di registrazione in una richiesta50
Richieste al minuto, errori, log, metriche (per progetto, ognuno)1200
Richieste al minuto, visite, registrazioni (per progetto, ognuna)600
Richieste al minuto da un indirizzo IP, tutta l'API300

Oltre un limite di dimensione la risposta è 413 e non si salva niente. Oltre un limite di frequenza la risposta è 429 con l'intestazione Retry-After, in secondi.

Con il gateway di ingest acceso, una richiesta può essere al massimo di 5 MB.

Quando qualcosa va storto

Una risposta di errore è così:

{ "error": { "code": "R422-LOG-004", "message": "…" } }
RispostaSignificaRimandare?
202accettatono
401token mancante, sbagliato o revocatono: correggi il token
403il token non può fare questa cosano
404il progetto nell'indirizzo non è quello del tokenno: correggi l'indirizzo
413troppi elementi in una richiestano: manda gruppi più piccoli
422il corpo non è JSON valido, o nessun elemento dentro è validono: correggi il corpo
429troppe richiestesì, dopo Retry-After secondi
500, 502, 503, 504, o nessuna rispostal'app è occupata o sta ripartendosì, con pause sempre più lunghe

Per ritentare senza doppioni tieni lo stesso event_id o sample_id: CloseYourIt ignora la copia se il primo tentativo era arrivato. Fanno eccezione i pezzi di registrazione: un pezzo rimandato può essere salvato due volte.

Rileggere i dati

Lo stesso token legge i dati del progetto. Ogni indirizzo restituisce gli ultimi 25 elementi.

IndirizzoFiltri
GET /api/v1/error_groupsstatus: unresolved, resolved, ignored
GET /api/v1/error_groups/<id>
GET /api/v1/metric_groupskind: slow_query, slow_method, performance_issue
GET /api/v1/log_entrieslevel, trace_id, environment
GET /api/v1/projects/<id>/analyticsrange: 24h, 7d, 30d, 1y; environment
curl -H "Authorization: Bearer $CYI_TOKEN" \
  "https://bugs.example.com/api/v1/error_groups?status=unresolved"

Per segnare un errore come risolto: PUT /api/v1/error_groups/<id>/resolution. Per riaprirlo: DELETE sullo stesso indirizzo.

Se vieni da Sentry

Le applicazioni che usano già un SDK di Sentry non hanno bisogno di questa pagina: tengono il loro SDK e cambiano un'impostazione. Vedi SDK Sentry.