Console API

The Console API provides a way to interact with the features of the Console programmatically. It is also used to send emails.

To get started, create an API key from the Console. Note that the API key is project-specific, meaning it can only be used with the project it was created in.

API Usage

  • API URL: https://relay.hyvor.com/api/console
  • Content-Type: application/json (both for requests and responses)
  • Authentication: Set the Authorization header with your API key as a Bearer token:
    Authorization: Bearer <your_api_key>

Scopes

Scopes are used to control access to endpoints of the Console API. When creating an API key, you can select the scopes that the key will have access to. The available scopes are:

  • sends.read
  • sends.send
  • domains.read
  • domains.write
  • webhooks.read
  • webhooks.write
  • api_keys.read
  • api_keys.write
  • suppressions.read
  • suppressions.write
  • analytics.read

Each endpoint requires specific scopes to be included in the API key.

Rate Limiting

The Console API has rate limits to prevent abuse and ensure fair usage.

  • Default rate limit: 100 requests per minute (per API key)
  • Email sending rate limit: 10 requests per second (per project)

If you exceed these limits, you will receive a 429 Too Many Requests response. The following standard headers are included in all API responses to indicate the current rate limit status:

  • X-RateLimit-Limit: The maximum number of requests allowed in the current time window.
  • X-RateLimit-Remaining: The number of requests remaining in the current time window.
  • X-RateLimit-Reset: How many seconds until the rate limit resets.

Endpoints

Sends (Emails)

Endpoints:

Objects:

Send Email

POST /sends (scope: sends.send)

Visit the Send Emails page for a detailed guide on how to send emails using this endpoint.

type Address = string | { email: string, name?: string };
type Request = {
	from: Address,
	to: Address | Address[],
	cc?: Address | Address[],
	bcc?: Address | Address[],
	subject?: string,
	body_html?: string,
	body_text?: string,
	headers?: Record<string, string>,
	attachments?: Array<{
		content: string, // base64 encoded
		name?: string,
		content_type?: string
	}>
}
type Response = {
	id: number,
	message_id: string
}

Get Sends

GET /sends (scope: sends.read)

type Request = {
    limit?: number, // Optional. Default is 50
    offset?: number, // Optional. Default is 0
    status?: 'queued' | 'processing' | 'accepted' | 'bounced' | 'complained', // Optional. Filter by status
    from_search?: string, // Optional. Search from address
    to_search?: string // Optional. Search to address
}
type Response = Send[]

Get Send by ID

GET /sends/:id (scope: sends.read)

type Request = {}
type Response = Send // includes attempts array

Get Send by UUID

GET /sends/uuid/:uuid (scope: sends.read)

type Request = {}
type Response = Send // includes attempts array

Domains

Endpoints:

Objects:

Get Domains

GET /domains (scope: domains.read)

type Request = {
    limit?: number, // Optional. Default is 50
    offset?: number, // Optional. Default is 0
    search?: string, // Optional. Search by domain name
}
type Response = Domain[]

Create Domain

POST /domains (scope: domains.write)

type Request = {
    domain: string
}
type Response = Domain

Verify Domain

POST /domains/verify (scope: domains.write)

type Request = {
	// Either id or domain must be provided
	id?: number,
	domain?: string
}
type Response = Domain

Get Domain

GET /domains/by (scope: domains.read)

type Request = {
	// Either id or domain must be provided
	id?: number,
	domain?: string
}
type Response = Domain
type Request = {}
type Response = Domain

Delete Domain

DELETE /domains (scope: domains.write)

type Request = {
	// Either id or domain must be provided
	id?: number,
	domain?: string
}
type Response = {}

Webhooks

Endpoints:

Objects:

Get Webhooks

GET /webhooks

type Request = {}
type Response = Webhook[]

Create Webhook

POST /webhooks

See Webhooks page for available events.

type Request = {
    url: string,
    description: string,
    events: string[]
}
type Response = Webhook

Update Webhook

PATCH /webhooks/:id

type Request = {
    url: string,
    description: string,
    events: string[]
}
type Response = Webhook

Delete Webhook

DELETE /webhooks/:id

type Request = {}
type Response = {}

Get Webhook Deliveries

GET /webhooks/deliveries

type Request = {
    webhook_id?: number // Optional. Filter by webhook ID
}
type Response = WebhookDelivery[]

API Keys

Endpoints:

Objects:

Get API Keys

GET /api-keys (scope: api_keys.read)

type Request = {}
type Response = ApiKey[]

Create API Key

POST /api-keys (scope: api_keys.write)

Note: Maximum of 10 API keys are allowed per project.

type Request = {
    name: string,
    scopes: string[]
}
type Response = ApiKey // includes the raw key only on creation

Update API Key

PATCH /api-keys/:id (scope: api_keys.write)

type Request = {
    name?: string,
    is_enabled?: boolean,
    scopes?: string[]
}
type Response = ApiKey

Delete API Key

DELETE /api-keys/:id (scope: api_keys.write)

type Request = {}
type Response = {}

Suppressions

Endpoints:

Objects:

Get Suppressions

GET /suppressions (scope: suppressions.read)

type Request = {
    email?: string, // Optional. Search by email
    reason?: 'bounce' | 'complaint' // Optional. Filter by reason
}
type Response = Suppression[]

Delete Suppression

DELETE /suppressions/:id (scope: suppressions.write)

type Request = {}
type Response = {}

Analytics

Endpoints:

Get Analytics Statistics

GET /analytics/stats (scope: analytics.read)

type Request = {}
type Response = {
    sends_30d: number,
    bounce_rate_30d: number,
    complaint_rate_30d: number
}

Get Analytics Chart Data

GET /analytics/sends/chart (scope: analytics.read)

type Request = {}
type Response = any // Chart data format

Objects

Send Object

interface Send = {
	id: number;
	uuid: string;
	created_at: number;
	sent_at: number | null;
	failed_at: number | null;
	status: 'queued' | 'accepted' | 'bounced' | 'complained';
	from_address: string;
	to_address: string;
	subject: string | null;
	body_html: string | null;
	body_text: string | null;
	raw: string;
	attempts: SendAttempt[];
}

SendRecipient Object

interface SendRecipient {
	id: number;
	type: 'to' | 'cc' | 'bcc';
	address: string;
	name: string;
	status: 'queued' | 'accepted' | 'retrying' | 'bounced' | 'complained' | 'failed';
	accepted_at: number | null;
	bounced_at: number | null;
	failed_at: number | null;
}

SendAttempt Object

interface SendAttempt {
	id: number;
	created_at: number;
	status: 'accepted' | 'deferred' | 'bounced' | 'failed';
	try_count: number;
	resolved_mx_hosts: string[];
	accepted_mx_host: string | null;
	smtp_conversations: Record<string, any>;
	error: string | null;
}

Bounce Object

interface Bounce {
    text: string;
    status: string;
}

Complaint Object

interface Complaint {
    text: string;
    feedback_type: string;
}

Domain Object

interface Domain {
	id: number;
	created_at: number;
	domain: string;
	status: 'pending' | 'active' | 'warning' | 'suspended';
	dkim_selector: string;
	dkim_host: string;
	dkim_public_key: string;
	dkim_txt_value: string;
	dkim_checked_at: number | null;
	dkim_error_message: string | null;
}

More about Domain Status.

Webhook Object

interface Webhook {
	id: number;
	url: string;
	description: string | null;
	events: string[];
}

WebhookDelivery Object

interface WebhookDelivery {
	id: number;
	created_at: number;
	url: string;
	event: string;
	status: 'pending' | 'delivered' | 'failed';
	response: string | null;
}

ApiKey Object

interface ApiKey {
	id: number;
	name: string;
	scopes: string[];
	key: string | null; // Only included when creating a new key
	created_at: number;
	is_enabled: boolean;
	last_accessed_at: number | null;
}

Suppression Object

interface Suppression {
	id: number;
	created_at: number;
	email: string;
	project: string;
	reason: 'bounce' | 'complaint';
	description: string | null;
}