Skip to main content

API Integration

Integrate with Resonance by sending events and receiving webhooks.


Authentication

All requests to the Resonance API must include a valid HMAC-SHA256 signature. Your security key is available in the Partner Portal under Settings > API Keys.

Include the signature in the X-Resonance-Signature request header. The signature is computed over the raw JSON payload body using your secret key.

const crypto = require('crypto');

function verifySignature(payload, signature, secretKey) {
const expected = crypto
.createHmac('sha256', secretKey)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}

Requests with missing or invalid signatures are rejected with a 401 INVALID_SIGNATURE response.


Sending Events

Send a POST request to the event handler endpoint to trigger a reward event for a Discord user.

Endpoint

POST https://api.resonance.bot/v1/events

Request Headers

HeaderValue
Content-Typeapplication/json
X-Resonance-SignatureHMAC-SHA256 hex signature of the request body

Request Body

{
"brand_id": "0x...",
"event_type": "custom_event",
"user_id": "discord_user_id",
"server_id": "guild_id",
"amount": 50,
"metadata": {}
}
FieldTypeRequiredDescription
brand_idstringYesYour brand's registered wallet address
event_typestringYesOne of the supported event types (see below)
user_idstringYesThe Discord user ID of the recipient
server_idstringYesThe Discord guild ID where the event occurred
amountnumberNoToken amount to award. Defaults to the event's configured amount if omitted.
metadataobjectNoArbitrary key-value data attached to the event record

Event Types

Event TypeDescription
daily_checkinDaily streak check-in
channel_messageMessage in monitored channel
message_qualityQuality message reward
reaction_thresholdMessage reached reaction threshold
boost_eventServer boost detected
voice_participationVoice channel activity
custom_eventCustom-defined event

Event types must be enabled for your brand before they can be triggered. Enable or disable event types via /config events in your Discord server.


Response Format

Success — 200 OK

{
"success": true,
"event_id": "evt_01HXYZ...",
"user_id": "discord_user_id",
"amount_awarded": 50,
"new_balance": 1250
}

Error — 4xx / 5xx

{
"success": false,
"error": {
"code": "COOLDOWN_ACTIVE",
"message": "User is currently in cooldown for this event type.",
"retry_after": 3420
}
}

HTTP Status Codes

StatusMeaning
200Event processed successfully
400Malformed request or invalid field values
401Signature verification failed
429Rate limit exceeded
500Internal server error

Rate Limits

Resonance enforces two layers of rate limiting to ensure fair distribution and prevent abuse.

Per-event cooldowns — Each event type has a configurable cooldown window per user. A user cannot trigger the same event type again until the cooldown expires. The retry_after field in error responses gives the remaining cooldown in seconds.

Per-user daily limits — Each user has a daily cap on the total number of reward events they can receive across all event types. Once a user reaches their daily limit, further events for that user are silently accepted but not processed until the following UTC day.

API-level limits — Requests from a single brand are limited to 60 requests per minute. Exceeding this returns a 429 response with a Retry-After header indicating when you may resume.

Cooldown durations and daily limits are configured per event type via /config events.


Error Codes

CodeDescriptionResolution
INVALID_SIGNATUREHMAC verification failedCheck that you are signing the correct payload with the correct security key from the Partner Portal
BRAND_NOT_FOUNDBrand ID not registeredVerify your brand_id matches the wallet address shown in the Partner Portal
EVENT_DISABLEDEvent type is disabledEnable the event type via /config events in your Discord server
COOLDOWN_ACTIVEUser is in cooldown for this eventWait for the cooldown period to expire; check retry_after in the response
INSUFFICIENT_BALANCEBrand wallet has insufficient fundsFund your brand wallet via the Partner Portal
USER_DISABLEDUser account is disabledCheck the user's status in the Partner Portal or via /user status