Eventos
Publica eventos y entrégalos a los suscriptores por webhook, consulta o transmisión en vivo, con mensajes muertos y reenvío.
Descripción general
Eventos permite que una parte de tu sistema anuncie que algo ocurrió, y que cada parte interesada se entere, sin que las dos se conozcan. Un publicador envía un evento como order.paid a https://events.inovacc.dev; cada suscripción cuyo patrón coincida con el tipo del evento lo recibe, por webhook a tu endpoint HTTPS, por pull desde tu worker, o por transmisión en vivo mediante un WebSocket. Los eventos que no se pueden entregar se conservan como mensajes muertos, que puedes inspeccionar y reproducir.
El problema que resuelve es la difusión confiable. Llamar directamente a cada servicio interesado los acopla, pierde mensajes cuando uno está caído y reintenta mal. Eventos acepta la publicación una vez, la entrega al menos una vez a cada suscripción, reintenta las entregas fallidas con espera creciente, deduplica las publicaciones repetidas y conserva lo que no pudo entregar.
Usa Eventos para reaccionar a los cambios: enviar un correo cuando se paga un pedido, refrescar una caché cuando cambia un registro, enviar una notificación a una página. Mantén el estado en sí en Datos y los bytes en Archivos: un evento debe decir qué ocurrió, no cargar el objeto. Para la historia completa del receptor de webhooks, consulta la guía de webhooks.
Conceptos
Espacio de trabajo. Todas las rutas están bajo /v1/workspaces/{workspace}. El espacio de trabajo en la ruta es una afirmación que se verifica contra tu credencial: una clave de aplicación puede nombrar solo su propio espacio de trabajo, y cualquier otro responde 403 forbidden, igual que uno que no existe.
Eventos y el envoltorio. Publicas type (palabras en minúscula separadas por puntos, como invoice.created, hasta 128 bytes), data (cualquier valor JSON) y un idempotency_key opcional. Los suscriptores reciben un envoltorio con event_id (evt_ y 26 caracteres, asignado por Inovacc), type, source (tu aplicación, establecida a partir de la credencial), time, tenant, idempotency_key y data.
Niveles. Una publicación puede nombrar un tier: basic (el predeterminado), reliable o advanced. El nivel fija el mayor data que puede llevar un evento: 16 KiB para basic y reliable, 32 KiB para advanced.
Suscripciones y patrones. Una suscripción lista de 1 a 20 patrones en types, cada uno * (todo), un tipo exacto, o un prefijo que termina en .* (order.* coincide con order.paid y order.item.added), y un modo de entrega.
Modos de entrega. webhook envía con POST cada evento a tu URL HTTPS, firmado con el secreto de la suscripción. pull mantiene un buzón que tu código lee y confirma. websocket mantiene el mismo buzón y además lo transmite en vivo; pull sigue funcionando junto a la transmisión.
Al menos una vez. Cada evento llega una vez a cada suscripción que coincide en operación normal, pero un reintento o una confirmación perdida puede entregarlo de nuevo. Los receptores deduplican por event_id.
Mensajes muertos. Una entrega de webhook que sigue fallando se mueve a los mensajes muertos de tu espacio de trabajo, con el último error y el número de intentos, y se conserva 30 días.
Cómo funciona
Toda llamada lleva Authorization: Bearer <credential>. La credencial es el tenant: la organización, la cuenta y la aplicación se obtienen de ella, y nada en un cuerpo puede nombrar a otra. Una clave secreta es para servidores y puede usar todas las rutas. Una clave publicable (apb_...) solo puede abrir una transmisión, desde un origen que su aplicación liste. El token de un usuario final no puede usar nada. Cada ruta necesita su propio permiso, como events:event.publish, events:subscription.write o events:dead.replay.
Publicar. POST /events con {"event": {...}} o {"events": [...]} (de 1 a 100). La respuesta es 202 con accepted (cada uno con su event_id y duplicate) y rejected (cada uno con un índice y un código); un evento incorrecto nunca bloquea a los demás. Enviar un idempotency_key ya usado en el espacio de trabajo en las últimas 168 horas devuelve el event_id original con duplicate: true y no entrega nada nuevo.
Entrega por webhook. Inovacc envía con POST el envoltorio a tu URL con x-event-id, x-event-type, x-event-timestamp y x-event-signature: v1=<hex>, un HMAC-SHA256 de la marca de tiempo y del cuerpo sin procesar. Cualquier 2xx dentro de 10 segundos es una entrega; cualquier otra cosa se reintenta después de 10 segundos, y la espera se duplica hasta 10 minutos, hasta que se alcanza el tope de 5 reintentos y el evento se convierte en un mensaje muerto. Las redirecciones nunca se siguen, y tu URL debe ser HTTPS pública en el puerto 443.
Pull. POST /subscriptions/{id}/pull con max (de 1 a 100, por defecto 10) y lease_seconds (de 5 a 300, por defecto 30) devuelve los mensajes más antiguos, cada uno con su delivery_count. Un mensaje obtenido queda oculto durante su arrendamiento; confírmalo con POST .../ack y los ids, o regresa cuando termina el arrendamiento.
Transmisión. GET /subscriptions/{id}/stream se actualiza a un WebSocket con el subprotocolo inovacc.v1; un navegador pasa su clave como un segundo subprotocolo, bearer.<key>. Cada trama es un envoltorio; responde {"ack": [...]} para confirmar. Una trama sin confirmar se vuelve a enviar después de su arrendamiento.
Monitoreo. GET /stats devuelve published, completed, depth, oldest_pending_age_seconds, retries, retry_rate y dlq_inflow para el espacio de trabajo. Cada llamada se registra en el Registro de actividad. Lo que se mide es el evento entregado.
Primeros pasos
Necesitas una clave secreta vinculada a tu espacio de trabajo con los permisos de eventos (Autenticación).
- Crea una suscripción pull.
POST /v1/workspaces/{workspace}/subscriptionscon{"types":["demo.*"],"delivery":{"mode":"pull"}}(consulta los ejemplos). La respuesta es 201 con unsubscription_id. - Publica.
POST .../eventscon{"event":{"type":"demo.hello","data":{"n":1}}}. La respuesta es 202 con una entrada enacceptedy suevent_id. - Obtén con pull.
POST .../subscriptions/{id}/pullcon{}. Tu evento está enmessages, condelivery_count1. - Confirma.
POST .../subscriptions/{id}/ackcon{"ids":["<event_id>"]}responde{"acked":1}; un segundo pull viene vacío. - Agrega un webhook. Crea una segunda suscripción con
{"mode":"webhook","url":"https://<your endpoint>"}, conserva elsigning_secretque la respuesta muestra una sola vez, y sigue la guía de webhooks para verificar las entregas.
Casos de uso
Cumplimiento de pedidos. El pago publica order.paid con el id del pedido en data y el id del pago como idempotency_key. Una suscripción por webhook para order.* llega al sistema del almacén; una suscripción pull alimenta el trabajo de facturación. Un pago reintentado por el cliente se publica una sola vez.
Actualizaciones en vivo en una página. Un panel abre una transmisión en una suscripción websocket para ticket.* con una clave publicable desde su propio origen, muestra cada ticket nuevo a medida que llega la trama, y la confirma.
Recuperación tras una caída. El endpoint de un socio estuvo caído una hora. Sus entregas terminaron en mensajes muertos con last_error webhook_timeout. Cuando vuelve, tu equipo lista GET /dead y reproduce cada evento; va solo a las suscripciones que nunca lo recibieron.
Límites y precios
| Límite | Valor |
|---|---|
| Eventos por publicación | 100 |
| Cuerpo de la solicitud | 5 MiB |
data por evento | 16 KiB (basic, reliable), 32 KiB (advanced) |
Ventana de deduplicación de idempotency_key | 168 horas |
| Suscripciones por espacio de trabajo; patrones por suscripción | 50; 20 |
| Mensajes por pull; arrendamiento | 100; de 5 a 300 segundos |
| Tiempo de respuesta del webhook | 10 segundos |
| Reintentos | desde 10 segundos, duplicándose hasta 10 minutos; tope de 5, luego mensaje muerto |
| Mensajes muertos conservados | 30 días |
| Trama de transmisión desde el cliente | 49,152 bytes |
| Tasa | 600 llamadas por minuto por credencial, por ubicación |
Precios: a consultar. La unidad de precio es el evento entregado.
Errores
| Estado | Código | Qué significa y qué hacer |
|---|---|---|
| 400 | invalid_body | El cuerpo está mal formado, o nombra source (proviene de tu credencial). |
| 400 | invalid_query | Solo GET /dead acepta una consulta (limit). |
| 400 | invalid_subscription, invalid_delivery, invalid_limit, invalid_id | Corrige la suscripción, la entrega o el parámetro. |
| 400 | invalid_url, url_not_https, url_has_credentials, url_port_not_allowed, url_destination_blocked | La URL del webhook debe ser HTTPS pública en el puerto 443, sin credenciales. |
| 401 | invalid_credentials | Envía una credencial válida. |
| 403 | forbidden, account_required | Falta un permiso o el espacio de trabajo es incorrecto; usa una clave de aplicación. |
| 403 | publishable_key_not_allowed, origin_not_allowed, secret_key_in_browser | Una clave publicable solo puede transmitir, desde un origen listado; mantén las claves secretas en servidores. |
| 404 | subscription_not_found, dead_event_not_found | No existe en tu espacio de trabajo. |
| 409 | wrong_delivery_mode, too_many_subscriptions, secret_not_managed | La operación no encaja con el modo de entrega, o estás en el tope de 50 suscripciones. |
| 413 | payload_too_large | El cuerpo supera 5 MiB. |
| 426 | upgrade_required | La ruta de transmisión necesita una actualización a WebSocket. |
| 429 | rate_limited, too_many_streams | Reduce el ritmo; cierra los sockets que no necesites. |
| 503 | service_unavailable, events_disabled, signing_unavailable | Reintenta más tarde; una publicación reintentada con las mismas claves reutiliza sus ids. |
Un evento rechazado dentro de un 202 lleva su propio código: invalid_event, unknown_field, invalid_type, invalid_idempotency_key, payload_too_large o data_required.
Buenas prácticas
- Envía un
idempotency_keyderivado de lo que ocurrió (el id del pago, la versión del registro), para que una publicación reintentada no sea un segundo evento. - Deduplica por
event_iden cada receptor: la entrega es al menos una vez. - Pon ids en
data, no objetos: obtén el estado actual desde Datos cuando manejes el evento. - Responde los webhooks rápido con un
2xxy haz el trabajo después; 10 segundos es el límite. - Verifica la firma de cada webhook antes de analizar el cuerpo (guía de webhooks).
- Confirma los mensajes obtenidos con pull después de procesarlos, y elige un arrendamiento más largo que tu tiempo de procesamiento.
- Vigila
depthydlq_inflowen/stats, y reproduce los mensajes muertos una vez corregida la causa.
Relacionados
- Guía de webhooks: recibe, verifica y reproduce entregas
- Datos, Registro de actividad
- Autenticación, Errores, Límites
Autenticación
Toda llamada lleva tu clave; tu organización viene de ella. Consulta la guía de autenticación.
AuthorizationEndpoints
POST /v1/workspaces/{workspace_id}/events
GET /v1/workspaces/{workspace_id}/subscriptions
POST /v1/workspaces/{workspace_id}/subscriptions
DELETE /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}
POST /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/rotate-secret
POST /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/pull
POST /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/ack
GET /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/stream
GET /v1/workspaces/{workspace_id}/dead
POST /v1/workspaces/{workspace_id}/dead/{event_id}/replay
GET /v1/workspaces/{workspace_id}/stats
Ejemplo
Lenguaje
⋮
cURL
curl -X POST "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events" \
-H "Authorization: Bearer $INOVACC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}'curl -X POST "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events" \
-H "Authorization: Bearer $INOVACC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}'
TypeScript
const body: Record<string, unknown> = {
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
};
const url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events";
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
console.log(response.status, await response.text());const body: Record<string, unknown> = {
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
};
const url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events";
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
console.log(response.status, await response.text());
Python
import json
import os
import urllib.request
body = {
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42",
},
},
}
request = urllib.request.Request(
"https://events.inovacc.dev/v1/workspaces/{workspace_id}/events",
data=json.dumps(body).encode(),
method="POST",
headers={
"User-Agent": "inovacc-python-sample",
"Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
"Content-Type": "application/json",
},
)
with urllib.request.urlopen(request) as response:
print(response.status, response.read().decode())import json
import os
import urllib.request
body = {
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42",
},
},
}
request = urllib.request.Request(
"https://events.inovacc.dev/v1/workspaces/{workspace_id}/events",
data=json.dumps(body).encode(),
method="POST",
headers={
"User-Agent": "inovacc-python-sample",
"Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
"Content-Type": "application/json",
},
)
with urllib.request.urlopen(request) as response:
print(response.status, response.read().decode())
Go
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
const url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events"
const body = `{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}`
func main() {
req, err := http.NewRequest("POST", url, strings.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
req.Header.Set("Content-Type", "application/json")
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"
"strings"
)
const url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events"
const body = `{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}`
func main() {
req, err := http.NewRequest("POST", url, strings.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
req.Header.Set("Content-Type", "application/json")
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"] }
// Cargo.toml: serde_json = "1"
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("INOVACC_API_KEY")?;
let body = serde_json::json!({
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
});
let response = reqwest::blocking::Client::new()
.post("https://events.inovacc.dev/v1/workspaces/{workspace_id}/events")
.bearer_auth(api_key)
.json(&body)
.send()?;
println!("{} {}", response.status(), response.text()?);
Ok(())
}// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
// Cargo.toml: serde_json = "1"
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("INOVACC_API_KEY")?;
let body = serde_json::json!({
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
});
let response = reqwest::blocking::Client::new()
.post("https://events.inovacc.dev/v1/workspaces/{workspace_id}/events")
.bearer_auth(api_key)
.json(&body)
.send()?;
println!("{} {}", response.status(), response.text()?);
Ok(())
}
JavaScript
const body = {
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
};
const url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events";
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
console.log(response.status, await response.text());const body = {
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
};
const url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events";
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
console.log(response.status, await response.text());
PHP
<?php
$body = <<<'JSON'
{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}
JSON;
$curl = curl_init('https://events.inovacc.dev/v1/workspaces/{workspace_id}/events');
curl_setopt_array($curl, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $body,
]);
$response = curl_exec($curl);
echo curl_getinfo($curl, CURLINFO_HTTP_CODE), ' ', $response, "\n";
curl_close($curl);<?php
$body = <<<'JSON'
{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}
JSON;
$curl = curl_init('https://events.inovacc.dev/v1/workspaces/{workspace_id}/events');
curl_setopt_array($curl, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $body,
]);
$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://events.inovacc.dev/v1/workspaces/{workspace_id}/events')
body = <<~'JSON'
{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}
JSON
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
request["Content-Type"] = "application/json"
request.body = body
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://events.inovacc.dev/v1/workspaces/{workspace_id}/events')
body = <<~'JSON'
{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}
JSON
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
request["Content-Type"] = "application/json"
request.body = body
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");
String body = "{" +
"\"event\": {" +
"\"type\": \"order.paid\"," +
"\"idempotency_key\": \"pay_123\"," +
"\"data\": {" +
"\"order_id\": \"ord_42\"" +
"}" +
"}" +
"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://events.inovacc.dev/v1/workspaces/{workspace_id}/events"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.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");
String body = "{" +
"\"event\": {" +
"\"type\": \"order.paid\"," +
"\"idempotency_key\": \"pay_123\"," +
"\"data\": {" +
"\"order_id\": \"ord_42\"" +
"}" +
"}" +
"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://events.inovacc.dev/v1/workspaces/{workspace_id}/events"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}
C#
using System.Text;
var body = "{" +
"\"event\": {" +
"\"type\": \"order.paid\"," +
"\"idempotency_key\": \"pay_123\"," +
"\"data\": {" +
"\"order_id\": \"ord_42\"" +
"}" +
"}" +
"}";
var url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events";
var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");using System.Text;
var body = "{" +
"\"event\": {" +
"\"type\": \"order.paid\"," +
"\"idempotency_key\": \"pay_123\"," +
"\"data\": {" +
"\"order_id\": \"ord_42\"" +
"}" +
"}" +
"}";
var url = "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events";
var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
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 body = "{" +
"\"event\": {" +
"\"type\": \"order.paid\"," +
"\"idempotency_key\": \"pay_123\"," +
"\"data\": {" +
"\"order_id\": \"ord_42\"" +
"}" +
"}" +
"}"
val request = HttpRequest.newBuilder()
.uri(URI.create("https://events.inovacc.dev/v1/workspaces/{workspace_id}/events"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.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 body = "{" +
"\"event\": {" +
"\"type\": \"order.paid\"," +
"\"idempotency_key\": \"pay_123\"," +
"\"data\": {" +
"\"order_id\": \"ord_42\"" +
"}" +
"}" +
"}"
val request = HttpRequest.newBuilder()
.uri(URI.create("https://events.inovacc.dev/v1/workspaces/{workspace_id}/events"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.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 body = #"""
{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}
"""#
let apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""
let url = URL(string: "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = Data(body.utf8)
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 body = #"""
{
"event": {
"type": "order.paid",
"idempotency_key": "pay_123",
"data": {
"order_id": "ord_42"
}
}
}
"""#
let apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""
let url = URL(string: "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = Data(body.utf8)
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))
Detalles de la fuente
- Id
- identity/component-taxonomy/capabilities#events
- Repositorio
- identity
- Ruta
- contracts/component-taxonomy/catalog/capabilities.json
- Commit
- 08ef3cd75d82
- Id
- identity/component-taxonomy/quickstart#events
- Repositorio
- identity
- Ruta
- contracts/component-taxonomy/catalog/capabilities.json
- Commit
- 08ef3cd75d82