RPC endpoint for agent account, project, user, and event operations.
Endpoint: /rpc
Auth
Type: Application-layer certificate signatures
Public methods: createUser
All RPC methods except createUser require a registered certificate fingerprint and a request signature made with the matching private key.
Create Certificate
Create a local P-256 self-signed certificate for the agent. The private key never leaves the agent.
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -keyout client.key -out client.pem -days 365 -nodes -subj "/CN=agent-name"
openssl x509 -in client.pem -noout -fingerprint -sha256
Store in 1Password
Store the generated key, public certificate, and fingerprint in a named 1Password item so humans and agents can discover them later.
OP_VAULT="Private"
SLASHEVENTS_ALIAS="agent-name"
SLASHEVENTS_FINGERPRINT="$(openssl x509 -in client.pem -noout -fingerprint -sha256 | cut -d= -f2)"
op item create \
--category "Secure Note" \
--vault "$OP_VAULT" \
--title "slashevents agent ${SLASHEVENTS_ALIAS}" \
--tags "slashevents,agent" \
"client.key[file]=./client.key" \
"client.pem[file]=./client.pem" \
"fingerprint[text]=${SLASHEVENTS_FINGERPRINT}"
Store in Apple Keychain
Import the certificate and private key as a non-exportable Keychain identity. Store the fingerprint separately for easy CLI lookup.
SLASHEVENTS_ALIAS="agent-name"
SLASHEVENTS_FINGERPRINT="$(openssl x509 -in client.pem -noout -fingerprint -sha256 | cut -d= -f2)"
P12="$(mktemp -t slashevents-agent.XXXXXX.p12)"
openssl pkcs12 -export \
-inkey ./client.key \
-in ./client.pem \
-name "slashevents agent ${SLASHEVENTS_ALIAS}" \
-out "$P12"
security import "$P12" \
-k "$HOME/Library/Keychains/login.keychain-db" \
-f pkcs12 \
-x
security add-generic-password \
-a "$SLASHEVENTS_ALIAS" \
-s "slashevents fingerprint" \
-l "slashevents agent ${SLASHEVENTS_ALIAS} fingerprint" \
-w "$SLASHEVENTS_FINGERPRINT" \
-U
rm -f "$P12"
Sign Up
Register an agent identity with its alias and public certificate.
curl https://slashevents.xyz/rpc \
-H 'Content-Type: application/json' \
-d "$(jq -n --rawfile cert client.pem '{method:"createUser", params:{alias:"agent-name", publicCertPem:$cert}}')"
Authenticated Request
Sign each authenticated request. The signed payload is METHOD, path with query, timestamp, and SHA-256 hex of the exact request body, joined with newline characters.
body='{"method":"getProjects","params":{}}'
fingerprint="$(openssl x509 -in client.pem -noout -fingerprint -sha256 | cut -d= -f2)"
timestamp="$(date +%s)"
body_sha256="$(printf '%s' "$body" | openssl dgst -sha256 -hex | awk '{print $2}')"
signing_string="$(printf 'POST\n/rpc\n%s\n%s' "$timestamp" "$body_sha256")"
signature="$(printf '%s' "$signing_string" | openssl dgst -sha256 -sign client.key | openssl base64 -A)"
curl https://slashevents.xyz/rpc \
-H "X-SlashEvents-Fingerprint: $fingerprint" \
-H "X-SlashEvents-Timestamp: $timestamp" \
-H "X-SlashEvents-Signature: $signature" \
-H 'Content-Type: application/json' \
-d "$body"
Authenticate with 1Password
Retrieve the key and certificate into a temporary directory, sign the request, and remove the temporary files when the shell exits.
OP_VAULT="Private"
SLASHEVENTS_ALIAS="agent-name"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
op read --out-file "$tmpdir/client.key" "op://${OP_VAULT}/slashevents agent ${SLASHEVENTS_ALIAS}/client.key"
op read --out-file "$tmpdir/client.pem" "op://${OP_VAULT}/slashevents agent ${SLASHEVENTS_ALIAS}/client.pem"
chmod 600 "$tmpdir/client.key" "$tmpdir/client.pem"
body='{"method":"getProjects","params":{}}'
fingerprint="$(openssl x509 -in "$tmpdir/client.pem" -noout -fingerprint -sha256 | cut -d= -f2)"
timestamp="$(date +%s)"
body_sha256="$(printf '%s' "$body" | openssl dgst -sha256 -hex | awk '{print $2}')"
signing_string="$(printf 'POST\n/rpc\n%s\n%s' "$timestamp" "$body_sha256")"
signature="$(printf '%s' "$signing_string" | openssl dgst -sha256 -sign "$tmpdir/client.key" | openssl base64 -A)"
curl https://slashevents.xyz/rpc \
-H "X-SlashEvents-Fingerprint: $fingerprint" \
-H "X-SlashEvents-Timestamp: $timestamp" \
-H "X-SlashEvents-Signature: $signature" \
-H 'Content-Type: application/json' \
-d "$body"
Authenticate with Apple Keychain
Use Keychain to discover the stored identity and fingerprint. Native macOS agents should sign with the Keychain identity through Security.framework instead of exporting the private key.
SLASHEVENTS_ALIAS="agent-name"
security find-identity -v -p ssl-client "$HOME/Library/Keychains/login.keychain-db" \
| grep "slashevents agent ${SLASHEVENTS_ALIAS}"
security find-generic-password \
-a "$SLASHEVENTS_ALIAS" \
-s "slashevents fingerprint" \
-w
Transport
Request
{
"id": "optional request id",
"method": "method name",
"params": {}
}
Success
{
"id": "optional request id",
"messages": [
{
"id": "01900000-0000-7000-8000-000000000000",
"payload": "operator-facing message"
}
],
"result": {}
}
Error
{
"id": "optional request id",
"messages": [
{
"id": "01900000-0000-7000-8000-000000000000",
"payload": "operator-facing message"
}
],
"error": {
"code": "ERROR_CODE",
"hint": "optional human-readable hint"
}
}
Every RPC response includes a top-level messages array. Each message has a UUIDv7 id and string payload. Agents should log non-empty messages, flag them for human review, then acknowledge them with ackMessages. Responses return a bounded message batch; if more messages are waiting, the batch includes an acknowledgeable overflow message telling the agent to request again after acknowledgement.
Billing
Projects are prepaid. Call getProjectBilling for the project deposit address, chain, token, balance, event price, and low-balance threshold. Ingress returns PAYMENT_REQUIRED when the project balance cannot cover another event.
Low-balance notices are returned through the response messages array. Agents should surface those notices to a human and acknowledge them with ackMessages after they have been handled.
Rate Limits
Authenticated RPC methods are rate-limited per agent. Public signup and malformed RPC requests are rate-limited per source IP. Rate-limited RPC calls return RATE_LIMIT_EXCEEDED with a retry hint.
Methods
ackMessages
Params
| Name | Type | Required | Values |
messageIds |
string/uuidv7[] |
yes |
|
Returns
| Name | Type | Required | Values |
ok |
boolean |
yes |
|
addUserToProject
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
userId |
string/uuidv7 |
yes |
|
permissions |
string/enum[] |
yes |
PROJECT_MANAGE_USERS, PROJECT_READ_USERS, PROJECT_READ_EVENTS |
Returns
| Name | Type | Required | Values |
ok |
boolean |
yes |
|
createProject
Params
| Name | Type | Required | Values |
name |
string |
yes |
|
Returns
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
createUser
Params
| Name | Type | Required | Values |
alias |
string |
yes |
|
publicCertPem |
string |
yes |
|
Returns
| Name | Type | Required | Values |
user |
object |
yes |
|
user.id |
string/uuidv7 |
yes |
|
user.alias |
string |
yes |
|
user.fingerprintSha256 |
string |
yes |
|
user.subject |
string | null |
yes |
|
user.certValidFrom |
string | null |
yes |
|
user.certValidTo |
string | null |
yes |
|
user.createdAt |
string |
yes |
|
user.revoked |
boolean |
yes |
|
user.revokedAt |
string | null |
yes |
|
getEvents
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
type |
string/enum |
no |
WEBHOOK_RECEIVED, PROJECT_CREATED, PROJECT_USER_ADDED, PROJECT_USER_REMOVED, PROJECT_USER_PERMISSION_GRANTED, PROJECT_USER_PERMISSION_REVOKED |
limit |
integer |
no |
|
cursor |
string |
no |
|
longPollDurationSeconds |
integer |
no |
|
Returns
| Name | Type | Required | Values |
events |
object[] |
yes |
|
events[].id |
string/uuidv7 |
yes |
|
events[].projectId |
string/uuidv7 |
yes |
|
events[].type |
string/enum |
yes |
WEBHOOK_RECEIVED, PROJECT_CREATED, PROJECT_USER_ADDED, PROJECT_USER_REMOVED, PROJECT_USER_PERMISSION_GRANTED, PROJECT_USER_PERMISSION_REVOKED |
events[].data |
unknown |
yes |
|
events[].receivedAt |
string |
yes |
|
events[].actorName |
string | null |
yes |
|
nextCursor |
string | null |
yes |
|
hasMore |
boolean |
yes |
|
getProject
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
Returns
| Name | Type | Required | Values |
project |
object |
yes |
|
project.id |
string/uuidv7 |
yes |
|
project.name |
string |
yes |
|
project.createdAt |
string |
yes |
|
project.webhookPathAllowlist |
string[] |
yes |
|
project.retentionConfig |
object |
yes |
|
project.retentionConfig.durationSeconds |
integer | null |
yes |
|
project.retentionConfig.maxEvents |
integer | null |
yes |
|
getProjectBilling
Returns the project billing deposit address, token details, balance, and global billing thresholds.
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
Returns
| Name | Type | Required | Values |
billing |
object |
yes |
|
billing.depositAddress |
string |
yes |
|
billing.chainId |
integer |
yes |
|
billing.tokenAddress |
string |
yes |
|
billing.tokenSymbol |
string |
yes |
|
billing.tokenDecimals |
integer |
yes |
|
billing.balanceAtomic |
string |
yes |
|
billing.eventPriceAtomic |
string |
yes |
|
billing.lowBalanceThresholdAtomic |
string |
yes |
|
getProjectRetentionConfig
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
Returns
| Name | Type | Required | Values |
retentionConfig |
object |
yes |
|
retentionConfig.durationSeconds |
integer | null |
yes |
|
retentionConfig.maxEvents |
integer | null |
yes |
|
getProjects
Params
| Name | Type | Required | Values |
cursor |
string/uuidv7 |
no |
|
limit |
integer |
no |
|
Returns
| Name | Type | Required | Values |
projects |
object[] |
yes |
|
projects[].id |
string/uuidv7 |
yes |
|
projects[].name |
string |
yes |
|
projects[].createdAt |
string |
yes |
|
nextCursor |
string/uuidv7 |
no |
|
getProjectUsers
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
cursor |
string/uuidv7 |
no |
|
limit |
integer |
no |
|
Returns
| Name | Type | Required | Values |
users |
object[] |
yes |
|
users[].userId |
string/uuidv7 |
yes |
|
users[].displayName |
string |
yes |
|
users[].permissions |
string/enum[] |
yes |
PROJECT_MANAGE_USERS, PROJECT_READ_USERS, PROJECT_READ_EVENTS |
nextCursor |
string/uuidv7 |
no |
|
getProjectWebhookPathAllowlist
Returns the project's webhook ingress allowlist as full-match regular expression path patterns.
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
Returns
| Name | Type | Required | Values |
webhookPathAllowlist |
string[] |
yes |
|
removeEvent
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
eventId |
string/uuidv7 |
yes |
|
Returns
| Name | Type | Required | Values |
ok |
boolean |
yes |
|
removeUserFromProject
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
userId |
string/uuidv7 |
yes |
|
Returns
| Name | Type | Required | Values |
ok |
boolean |
yes |
|
setProjectRetentionConfig
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
retentionConfig |
object |
yes |
|
retentionConfig.durationSeconds |
integer | null |
yes |
|
retentionConfig.maxEvents |
integer | null |
yes |
|
Returns
| Name | Type | Required | Values |
retentionConfig |
object |
yes |
|
retentionConfig.durationSeconds |
integer | null |
yes |
|
retentionConfig.maxEvents |
integer | null |
yes |
|
setProjectWebhookPathAllowlist
Sets the project's webhook ingress allowlist. paths entries are full-match regular expression patterns evaluated against the path after /ingress/{projectId}. Literal paths such as /stripe/hooks work; use patterns such as /customers/[^/]+/events for paths with IDs.
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
paths |
string[] |
yes |
|
Returns
| Name | Type | Required | Values |
webhookPathAllowlist |
string[] |
yes |
|
updateProjectUserPermissions
Params
| Name | Type | Required | Values |
projectId |
string/uuidv7 |
yes |
|
userId |
string/uuidv7 |
yes |
|
permissions |
string/enum[] |
yes |
PROJECT_MANAGE_USERS, PROJECT_READ_USERS, PROJECT_READ_EVENTS |
Returns
| Name | Type | Required | Values |
ok |
boolean |
yes |
|