Events
Publish events and deliver them to subscribers by webhook, pull or live stream, with dead letters and replay.
Overview
Events lets one part of your system announce that something happened, and lets every interested part hear about it, without the two knowing each other. A publisher sends an event such as order.paid to https://events.inovacc.dev; every subscription whose pattern matches the event's type receives it, by webhook to your HTTPS endpoint, by pull from your worker, or by live stream over a WebSocket. Events that cannot be delivered are kept as dead letters, which you can inspect and replay.
The problem it solves is reliable fan-out. Calling each interested service directly couples them, loses messages when one is down and retries badly. Events accepts the publish once, delivers it at least once to each subscription, retries failed deliveries with backoff, deduplicates repeated publishes, and keeps what it could not deliver.
Use Events to react to what happens in your system. Send an email when an order is paid, refresh a cache when a record changes, push a notification to a page. Keep the state itself in Data and the bytes in Files: an event should say what happened, not carry the object. For the full webhook receiver story, see the Webhooks guide.
Concepts
Workspace. Every route is under /v1/workspaces/{workspace}. The workspace in the path is a claim checked against your credential: an application key may name only its own workspace, and any other answers 403 forbidden, the same as one that does not exist.
Events and the envelope. You publish type (dotted lowercase words, such as invoice.created, up to 128 bytes), data (any JSON value) and an optional idempotency_key. Subscribers receive an envelope with event_id (evt_ and 26 characters, assigned by Inovacc), type, source (your application, set from the credential), time, tenant, idempotency_key and data.
Tiers. A publish may name a tier: basic (the default), reliable or advanced. The tier sets the largest data an event may carry: 16 KiB for basic and reliable, 32 KiB for advanced.
Subscriptions and patterns. A subscription lists 1 to 20 types patterns, each * (everything), an exact type, or a prefix ending in .* (order.* matches order.paid and order.item.added), and one delivery mode.
Delivery modes. webhook posts each event to your HTTPS URL, signed with the subscription's secret. pull keeps an inbox your code reads and acknowledges. websocket keeps the same inbox and also streams it live; pull keeps working beside the stream.
At least once. Each event reaches each matching subscription once under normal operation, but a retry or a lost acknowledgement can deliver it again. Receivers deduplicate by event_id.
Dead letters. A webhook delivery that keeps failing is moved to your workspace's dead letters, with the last error and the number of attempts, and kept 30 days.
How it works
Every call carries Authorization: Bearer <credential>. The credential is the tenant: organization, account and application come from it, and nothing in a body can name another. A secret key is for servers and may use every route. A publishable key (apb_...) may only open a stream, from an origin its application lists. An end user's token may use nothing. Each route needs its own permission, such as events:event.publish, events:subscription.write or events:dead.replay.
Publish. POST /events with {"event": {...}} or {"events": [...]} (1 to 100). The answer is 202 with accepted (each with its event_id and duplicate) and rejected (each with an index and a code); a bad event never blocks the others. Sending an idempotency_key already used in the workspace in the last 168 hours returns the original event_id with duplicate: true and delivers nothing new.
Webhook delivery. Inovacc posts the envelope to your URL with x-event-id, x-event-type, x-event-timestamp and x-event-signature: v1=<hex>, an HMAC-SHA256 of the timestamp and the raw body. Any 2xx within 10 seconds is a delivery; anything else is retried after 10 seconds, the delay doubling up to 10 minutes, until the retry cap of 5 is reached and the event becomes a dead letter. Redirects are never followed, and your URL must be public HTTPS on port 443.
Pull. POST /subscriptions/{id}/pull with max (1 to 100, default 10) and lease_seconds (5 to 300, default 30) returns the oldest messages, each with its delivery_count. A pulled message is hidden for its lease; acknowledge it with POST .../ack and the ids, or it returns when the lease ends.
Stream. GET /subscriptions/{id}/stream upgrades to a WebSocket with the subprotocol inovacc.v1; a browser passes its key as a second subprotocol, bearer.<key>. Each frame is one envelope; reply {"ack": [...]} to acknowledge. An unacknowledged frame is sent again after its lease.
Monitor. GET /stats returns published, completed, depth, oldest_pending_age_seconds, retries, retry_rate and dlq_inflow for the workspace. Every call is recorded in the Activity log. What is metered is the delivered event.
Get started
You need a secret key bound to your workspace with the events permissions (Authentication).
- Create a pull subscription.
POST /v1/workspaces/{workspace}/subscriptionswith{"types":["demo.*"],"delivery":{"mode":"pull"}}(see the samples). The answer is 201 with asubscription_id. - Publish.
POST .../eventswith{"event":{"type":"demo.hello","data":{"n":1}}}. The answer is 202 with oneacceptedentry and itsevent_id. - Pull.
POST .../subscriptions/{id}/pullwith{}. Your event is inmessages, withdelivery_count1. - Acknowledge.
POST .../subscriptions/{id}/ackwith{"ids":["<event_id>"]}answers{"acked":1}; a second pull is empty. - Add a webhook. Create a second subscription with
{"mode":"webhook","url":"https://<your endpoint>"}, keep thesigning_secretthe answer shows once, and follow the Webhooks guide to verify deliveries.
Use cases
Order fulfilment. The checkout publishes order.paid with the order id in data and the payment id as idempotency_key. A webhook subscription for order.* reaches the warehouse system; a pull subscription feeds the invoicing job. A checkout retried by the customer publishes once.
Live updates in a page. A dashboard opens a stream on a websocket subscription for ticket.* with a publishable key from its own origin, shows each new ticket as the frame arrives, and acknowledges it.
Recovering from an outage. A partner's endpoint was down for an hour. Its deliveries ended in dead letters with last_error webhook_timeout. Once it is back, your team lists GET /dead and replays each event; it goes only to the subscriptions that never received it.
Limits and pricing
| Limit | Value |
|---|---|
| Events per publish | 100 |
| Request body | 5 MiB |
data per event | 16 KiB (basic, reliable), 32 KiB (advanced) |
Deduplication window for idempotency_key | 168 hours |
| Subscriptions per workspace; patterns per subscription | 50; 20 |
| Messages per pull; lease | 100; 5 to 300 seconds |
| Webhook response time | 10 seconds |
| Retries | from 10 seconds, doubling to 10 minutes; cap 5, then dead letter |
| Dead letters kept | 30 days |
| Stream frame from the client | 49,152 bytes |
| Rate | 600 calls per minute per credential, per location |
Pricing: on request. The pricing unit is the delivered event.
Errors
| Status | Code | What it means and what to do |
|---|---|---|
| 400 | invalid_body | The body is malformed, or names source (it comes from your credential). |
| 400 | invalid_query | Only GET /dead takes a query (limit). |
| 400 | invalid_subscription, invalid_delivery, invalid_limit, invalid_id | Fix the subscription, the delivery or the parameter. |
| 400 | invalid_url, url_not_https, url_has_credentials, url_port_not_allowed, url_destination_blocked | The webhook URL must be public HTTPS on port 443, without credentials. |
| 401 | invalid_credentials | Send a valid credential. |
| 403 | forbidden, account_required | Missing permission or wrong workspace; use an application key. |
| 403 | publishable_key_not_allowed, origin_not_allowed, secret_key_in_browser | A publishable key may only stream, from a listed origin; keep secret keys on servers. |
| 404 | subscription_not_found, dead_event_not_found | It does not exist in your workspace. |
| 409 | wrong_delivery_mode, too_many_subscriptions, secret_not_managed | The operation does not fit the delivery mode, or you are at 50 subscriptions. |
| 413 | payload_too_large | The body is over 5 MiB. |
| 426 | upgrade_required | The stream route needs a WebSocket upgrade. |
| 429 | rate_limited, too_many_streams | Slow down; close sockets you do not need. |
| 503 | service_unavailable, events_disabled, signing_unavailable | Retry later; a publish retried with the same keys reuses its ids. |
A rejected event inside a 202 carries its own code: invalid_event, unknown_field, invalid_type, invalid_idempotency_key, payload_too_large or data_required.
Best practices
- Send an
idempotency_keyderived from what happened (the payment id, the record version), so a retried publish is not a second event. - Deduplicate by
event_idin every receiver: delivery is at least once. - Put ids in
data, not objects: fetch the current state from Data when you handle the event. - Answer webhooks fast with a
2xxand do the work afterwards; 10 seconds is the limit. - Verify every webhook signature before parsing the body (Webhooks guide).
- Acknowledge pulled messages after processing, and choose a lease longer than your processing time.
- Watch
depthanddlq_inflowin/stats, and replay dead letters once the cause is fixed.
Related
- Webhooks guide: receive, verify and replay deliveries
- Data, Activity log
- Authentication, Errors, Limits
Authentication
Every call carries your key; your organization comes from it. See the authentication guide.
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
Example
Language
⋮
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))
Source details
- Id
- identity/component-taxonomy/capabilities#events
- Repository
- identity
- Path
- contracts/component-taxonomy/catalog/capabilities.json
- Commit
- 08ef3cd75d82
- Id
- identity/component-taxonomy/quickstart#events
- Repository
- identity
- Path
- contracts/component-taxonomy/catalog/capabilities.json
- Commit
- 08ef3cd75d82