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