feat: BlackRoad Zapier App v1.0.0
Official Zapier integration enabling 5000+ app connections. Triggers: - new_user: New user signup - deployment_complete: Deployment finished - error_occurred: Error detected - agent_status_change: AI agent status update - usage_threshold: Usage limit exceeded Actions: - deploy_product: Trigger deployments - create_user: Add users - update_config: Change settings - send_notification: Send alerts - scale_agents: Scale AI agents Searches: - find_user: Search users - find_deployment: Search deployments
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
.zapierapprc
|
||||||
67
README.md
Normal file
67
README.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# BlackRoad Zapier App
|
||||||
|
|
||||||
|
Official Zapier integration for BlackRoad OS - connect AI infrastructure to 5000+ apps.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Triggers (Start a Zap when...)
|
||||||
|
| Trigger | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| New User | A new user signs up |
|
||||||
|
| Deployment Complete | A deployment finishes |
|
||||||
|
| Error Occurred | An error is detected |
|
||||||
|
| Agent Status Change | An AI agent's status changes |
|
||||||
|
| Usage Threshold | Usage exceeds your limit |
|
||||||
|
|
||||||
|
### Actions (Do this...)
|
||||||
|
| Action | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| Deploy Product | Trigger a deployment |
|
||||||
|
| Create User | Add a new user |
|
||||||
|
| Update Config | Change configuration |
|
||||||
|
| Send Notification | Send alerts (Slack/email) |
|
||||||
|
| Scale Agents | Scale AI agents up/down |
|
||||||
|
|
||||||
|
### Searches (Find...)
|
||||||
|
| Search | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| Find User | Search by email or ID |
|
||||||
|
| Find Deployment | Search by ID or service |
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Go to [Zapier](https://zapier.com/apps/blackroad/integrations)
|
||||||
|
2. Click "Connect BlackRoad"
|
||||||
|
3. Enter your API key from https://blackroad.io/settings/api
|
||||||
|
|
||||||
|
## Example Zaps
|
||||||
|
|
||||||
|
- **Slack + BlackRoad**: Get Slack notifications when deployments complete
|
||||||
|
- **Email + BlackRoad**: Email team when errors occur
|
||||||
|
- **Google Sheets + BlackRoad**: Log new users to a spreadsheet
|
||||||
|
- **Airtable + BlackRoad**: Track agent status changes
|
||||||
|
- **PagerDuty + BlackRoad**: Alert on-call when critical errors occur
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Test locally
|
||||||
|
npm test
|
||||||
|
|
||||||
|
# Validate app
|
||||||
|
npm run validate
|
||||||
|
|
||||||
|
# Push to Zapier
|
||||||
|
npm run push
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Base URL
|
||||||
|
|
||||||
|
`https://api.blackroad.io/v1/`
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT © BlackRoad OS, Inc.
|
||||||
94
actions/create_user.js
Normal file
94
actions/create_user.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
* Action: Create User
|
||||||
|
* Create a new user in BlackRoad
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'create_user',
|
||||||
|
noun: 'User',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Create User',
|
||||||
|
description: 'Create a new user in your BlackRoad organization.',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
label: 'Email',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
label: 'Name',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'role',
|
||||||
|
label: 'Role',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['admin', 'developer', 'viewer'],
|
||||||
|
default: 'developer',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'products',
|
||||||
|
label: 'Products',
|
||||||
|
type: 'string',
|
||||||
|
list: true,
|
||||||
|
choices: ['vllm', 'api', 'agents', 'dashboard'],
|
||||||
|
helpText: 'Which products this user can access',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'send_invite',
|
||||||
|
label: 'Send Invite Email',
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/users`,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
email: bundle.inputData.email,
|
||||||
|
name: bundle.inputData.name,
|
||||||
|
role: bundle.inputData.role,
|
||||||
|
products: bundle.inputData.products,
|
||||||
|
send_invite: bundle.inputData.send_invite,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json;
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'user_new123',
|
||||||
|
email: 'newuser@example.com',
|
||||||
|
name: 'New User',
|
||||||
|
role: 'developer',
|
||||||
|
products: ['vllm', 'api'],
|
||||||
|
created_at: '2026-02-15T10:00:00Z',
|
||||||
|
invite_sent: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'User ID', type: 'string' },
|
||||||
|
{ key: 'email', label: 'Email', type: 'string' },
|
||||||
|
{ key: 'name', label: 'Name', type: 'string' },
|
||||||
|
{ key: 'role', label: 'Role', type: 'string' },
|
||||||
|
{ key: 'products', label: 'Products', type: 'string' },
|
||||||
|
{ key: 'created_at', label: 'Created At', type: 'datetime' },
|
||||||
|
{ key: 'invite_sent', label: 'Invite Sent', type: 'boolean' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
96
actions/deploy_product.js
Normal file
96
actions/deploy_product.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Action: Deploy Product
|
||||||
|
* Trigger a deployment for a BlackRoad service
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'deploy_product',
|
||||||
|
noun: 'Deployment',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Deploy Product',
|
||||||
|
description: 'Trigger a deployment for a BlackRoad service.',
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'service',
|
||||||
|
label: 'Service',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
'blackroad-api',
|
||||||
|
'blackroad-dashboard',
|
||||||
|
'blackroad-agents',
|
||||||
|
'blackroad-vllm',
|
||||||
|
'blackroad-landing',
|
||||||
|
],
|
||||||
|
helpText: 'The service to deploy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'environment',
|
||||||
|
label: 'Environment',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['production', 'staging', 'development'],
|
||||||
|
default: 'production',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'version',
|
||||||
|
label: 'Version',
|
||||||
|
type: 'string',
|
||||||
|
helpText: 'Version tag (optional, defaults to latest)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'notify_slack',
|
||||||
|
label: 'Notify Slack',
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
helpText: 'Send deployment notification to Slack',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/deployments`,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
service: bundle.inputData.service,
|
||||||
|
environment: bundle.inputData.environment,
|
||||||
|
version: bundle.inputData.version,
|
||||||
|
notify_slack: bundle.inputData.notify_slack,
|
||||||
|
source: 'zapier',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json;
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'deploy_xyz789',
|
||||||
|
service: 'blackroad-api',
|
||||||
|
environment: 'production',
|
||||||
|
version: 'v1.2.3',
|
||||||
|
status: 'in_progress',
|
||||||
|
started_at: '2026-02-15T10:00:00Z',
|
||||||
|
estimated_duration: 180,
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'Deployment ID', type: 'string' },
|
||||||
|
{ key: 'service', label: 'Service', type: 'string' },
|
||||||
|
{ key: 'environment', label: 'Environment', type: 'string' },
|
||||||
|
{ key: 'version', label: 'Version', type: 'string' },
|
||||||
|
{ key: 'status', label: 'Status', type: 'string' },
|
||||||
|
{ key: 'started_at', label: 'Started At', type: 'datetime' },
|
||||||
|
{ key: 'estimated_duration', label: 'Estimated Duration (s)', type: 'integer' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
79
actions/scale_agents.js
Normal file
79
actions/scale_agents.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Action: Scale Agents
|
||||||
|
* Scale the number of AI agents up or down
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'scale_agents',
|
||||||
|
noun: 'Agent Pool',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Scale Agents',
|
||||||
|
description: 'Scale the number of AI agents up or down.',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'agent_type',
|
||||||
|
label: 'Agent Type',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
choices: ['infrastructure', 'code_review', 'security', 'analytics', 'general'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'target_count',
|
||||||
|
label: 'Target Count',
|
||||||
|
type: 'integer',
|
||||||
|
required: true,
|
||||||
|
helpText: 'The desired number of agents',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'scaling_policy',
|
||||||
|
label: 'Scaling Policy',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['immediate', 'gradual'],
|
||||||
|
default: 'gradual',
|
||||||
|
helpText: 'How quickly to scale',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/agents/scale`,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
agent_type: bundle.inputData.agent_type,
|
||||||
|
target_count: bundle.inputData.target_count,
|
||||||
|
scaling_policy: bundle.inputData.scaling_policy,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json;
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
agent_type: 'infrastructure',
|
||||||
|
previous_count: 5,
|
||||||
|
target_count: 10,
|
||||||
|
scaling_policy: 'gradual',
|
||||||
|
status: 'scaling',
|
||||||
|
estimated_completion: '2026-02-15T10:05:00Z',
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'agent_type', label: 'Agent Type', type: 'string' },
|
||||||
|
{ key: 'previous_count', label: 'Previous Count', type: 'integer' },
|
||||||
|
{ key: 'target_count', label: 'Target Count', type: 'integer' },
|
||||||
|
{ key: 'scaling_policy', label: 'Scaling Policy', type: 'string' },
|
||||||
|
{ key: 'status', label: 'Status', type: 'string' },
|
||||||
|
{ key: 'estimated_completion', label: 'Estimated Completion', type: 'datetime' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
96
actions/send_notification.js
Normal file
96
actions/send_notification.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Action: Send Notification
|
||||||
|
* Send a notification through BlackRoad channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'send_notification',
|
||||||
|
noun: 'Notification',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Send Notification',
|
||||||
|
description: 'Send a notification through BlackRoad (Slack, email, webhook).',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'channel',
|
||||||
|
label: 'Channel',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
choices: ['slack', 'email', 'webhook', 'all'],
|
||||||
|
default: 'slack',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'title',
|
||||||
|
label: 'Title',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'message',
|
||||||
|
label: 'Message',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'severity',
|
||||||
|
label: 'Severity',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['info', 'warning', 'error', 'critical'],
|
||||||
|
default: 'info',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'recipients',
|
||||||
|
label: 'Recipients',
|
||||||
|
type: 'string',
|
||||||
|
list: true,
|
||||||
|
helpText: 'Email addresses or Slack channels (optional)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/notifications`,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
channel: bundle.inputData.channel,
|
||||||
|
title: bundle.inputData.title,
|
||||||
|
message: bundle.inputData.message,
|
||||||
|
severity: bundle.inputData.severity,
|
||||||
|
recipients: bundle.inputData.recipients,
|
||||||
|
source: 'zapier',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json;
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'notif_abc123',
|
||||||
|
channel: 'slack',
|
||||||
|
title: 'Deployment Complete',
|
||||||
|
message: 'The deployment was successful!',
|
||||||
|
severity: 'info',
|
||||||
|
sent_at: '2026-02-15T10:00:00Z',
|
||||||
|
delivered: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'Notification ID', type: 'string' },
|
||||||
|
{ key: 'channel', label: 'Channel', type: 'string' },
|
||||||
|
{ key: 'title', label: 'Title', type: 'string' },
|
||||||
|
{ key: 'message', label: 'Message', type: 'string' },
|
||||||
|
{ key: 'severity', label: 'Severity', type: 'string' },
|
||||||
|
{ key: 'sent_at', label: 'Sent At', type: 'datetime' },
|
||||||
|
{ key: 'delivered', label: 'Delivered', type: 'boolean' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
89
actions/update_config.js
Normal file
89
actions/update_config.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Action: Update Config
|
||||||
|
* Update configuration for a BlackRoad service
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'update_config',
|
||||||
|
noun: 'Config',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Update Configuration',
|
||||||
|
description: 'Update configuration settings for a BlackRoad service.',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'service',
|
||||||
|
label: 'Service',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
'blackroad-api',
|
||||||
|
'blackroad-agents',
|
||||||
|
'blackroad-vllm',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'key',
|
||||||
|
label: 'Config Key',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
helpText: 'The configuration key to update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'value',
|
||||||
|
label: 'Value',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
helpText: 'The new value',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'environment',
|
||||||
|
label: 'Environment',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['production', 'staging', 'development'],
|
||||||
|
default: 'production',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/config/${bundle.inputData.service}`,
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
key: bundle.inputData.key,
|
||||||
|
value: bundle.inputData.value,
|
||||||
|
environment: bundle.inputData.environment,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json;
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
service: 'blackroad-api',
|
||||||
|
key: 'rate_limit',
|
||||||
|
value: '1000',
|
||||||
|
environment: 'production',
|
||||||
|
updated_at: '2026-02-15T10:00:00Z',
|
||||||
|
updated_by: 'zapier',
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'service', label: 'Service', type: 'string' },
|
||||||
|
{ key: 'key', label: 'Config Key', type: 'string' },
|
||||||
|
{ key: 'value', label: 'Value', type: 'string' },
|
||||||
|
{ key: 'environment', label: 'Environment', type: 'string' },
|
||||||
|
{ key: 'updated_at', label: 'Updated At', type: 'datetime' },
|
||||||
|
{ key: 'updated_by', label: 'Updated By', type: 'string' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
74
index.js
Normal file
74
index.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* BlackRoad Zapier App
|
||||||
|
* Official integration for connecting BlackRoad OS to 5000+ apps
|
||||||
|
*/
|
||||||
|
|
||||||
|
const authentication = require('./lib/authentication');
|
||||||
|
|
||||||
|
// Triggers
|
||||||
|
const newUserTrigger = require('./triggers/new_user');
|
||||||
|
const deploymentCompleteTrigger = require('./triggers/deployment_complete');
|
||||||
|
const errorOccurredTrigger = require('./triggers/error_occurred');
|
||||||
|
const agentStatusChangeTrigger = require('./triggers/agent_status_change');
|
||||||
|
const usageThresholdTrigger = require('./triggers/usage_threshold');
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
const deployProductAction = require('./actions/deploy_product');
|
||||||
|
const createUserAction = require('./actions/create_user');
|
||||||
|
const updateConfigAction = require('./actions/update_config');
|
||||||
|
const sendNotificationAction = require('./actions/send_notification');
|
||||||
|
const scaleAgentsAction = require('./actions/scale_agents');
|
||||||
|
|
||||||
|
// Searches
|
||||||
|
const findUserSearch = require('./searches/find_user');
|
||||||
|
const findDeploymentSearch = require('./searches/find_deployment');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
version: require('./package.json').version,
|
||||||
|
platformVersion: require('zapier-platform-core').version,
|
||||||
|
|
||||||
|
authentication: authentication,
|
||||||
|
|
||||||
|
// Branding
|
||||||
|
beforeRequest: [
|
||||||
|
(request, z, bundle) => {
|
||||||
|
request.headers['X-BlackRoad-Source'] = 'zapier';
|
||||||
|
request.headers['X-BlackRoad-Version'] = '1.0.0';
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
afterResponse: [
|
||||||
|
(response, z, bundle) => {
|
||||||
|
if (response.status >= 400) {
|
||||||
|
const message = response.json?.error?.message || 'Unknown error';
|
||||||
|
throw new z.errors.Error(message, 'ApiError', response.status);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// Triggers - events that start a Zap
|
||||||
|
triggers: {
|
||||||
|
[newUserTrigger.key]: newUserTrigger,
|
||||||
|
[deploymentCompleteTrigger.key]: deploymentCompleteTrigger,
|
||||||
|
[errorOccurredTrigger.key]: errorOccurredTrigger,
|
||||||
|
[agentStatusChangeTrigger.key]: agentStatusChangeTrigger,
|
||||||
|
[usageThresholdTrigger.key]: usageThresholdTrigger,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Actions - things the Zap can do
|
||||||
|
creates: {
|
||||||
|
[deployProductAction.key]: deployProductAction,
|
||||||
|
[createUserAction.key]: createUserAction,
|
||||||
|
[updateConfigAction.key]: updateConfigAction,
|
||||||
|
[sendNotificationAction.key]: sendNotificationAction,
|
||||||
|
[scaleAgentsAction.key]: scaleAgentsAction,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Searches - find specific records
|
||||||
|
searches: {
|
||||||
|
[findUserSearch.key]: findUserSearch,
|
||||||
|
[findDeploymentSearch.key]: findDeploymentSearch,
|
||||||
|
},
|
||||||
|
};
|
||||||
61
lib/authentication.js
Normal file
61
lib/authentication.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* BlackRoad Zapier Authentication
|
||||||
|
* API Key-based authentication
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
const authentication = {
|
||||||
|
type: 'custom',
|
||||||
|
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'apiKey',
|
||||||
|
label: 'API Key',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
helpText: 'Your BlackRoad API key. Find it at https://blackroad.io/settings/api',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'orgId',
|
||||||
|
label: 'Organization ID',
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
helpText: 'Optional: Your organization ID for team accounts',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
test: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/auth/verify`,
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new z.errors.Error('Invalid API key', 'AuthenticationError', response.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json;
|
||||||
|
},
|
||||||
|
|
||||||
|
connectionLabel: (z, bundle) => {
|
||||||
|
return bundle.inputData.email || bundle.inputData.org_name || 'BlackRoad Account';
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to add auth headers to all requests
|
||||||
|
const addAuthHeaders = (request, z, bundle) => {
|
||||||
|
if (bundle.authData.apiKey) {
|
||||||
|
request.headers.Authorization = `Bearer ${bundle.authData.apiKey}`;
|
||||||
|
}
|
||||||
|
if (bundle.authData.orgId) {
|
||||||
|
request.headers['X-BlackRoad-Org'] = bundle.authData.orgId;
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = authentication;
|
||||||
|
module.exports.addAuthHeaders = addAuthHeaders;
|
||||||
30
package.json
Normal file
30
package.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "blackroad-zapier-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Official BlackRoad Zapier Integration - Connect AI infrastructure to 5000+ apps",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "zapier test",
|
||||||
|
"validate": "zapier validate",
|
||||||
|
"push": "zapier push",
|
||||||
|
"describe": "zapier describe"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"blackroad",
|
||||||
|
"zapier",
|
||||||
|
"integration",
|
||||||
|
"ai",
|
||||||
|
"automation"
|
||||||
|
],
|
||||||
|
"author": "BlackRoad OS, Inc.",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"zapier-platform-core": "^15.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"zapier-platform-cli": "^15.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
67
searches/find_deployment.js
Normal file
67
searches/find_deployment.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Search: Find Deployment
|
||||||
|
* Search for a deployment by ID or service
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'find_deployment',
|
||||||
|
noun: 'Deployment',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Find Deployment',
|
||||||
|
description: 'Find a deployment by ID or service.',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'deployment_id',
|
||||||
|
label: 'Deployment ID',
|
||||||
|
type: 'string',
|
||||||
|
helpText: 'Search by deployment ID',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service',
|
||||||
|
label: 'Service',
|
||||||
|
type: 'string',
|
||||||
|
helpText: 'Search by service name (returns most recent)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/deployments/search`,
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
id: bundle.inputData.deployment_id,
|
||||||
|
service: bundle.inputData.service,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json.deployments || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'deploy_xyz789',
|
||||||
|
service: 'blackroad-api',
|
||||||
|
version: 'v1.2.3',
|
||||||
|
status: 'success',
|
||||||
|
environment: 'production',
|
||||||
|
completed_at: '2026-02-15T10:00:00Z',
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'Deployment ID', type: 'string' },
|
||||||
|
{ key: 'service', label: 'Service', type: 'string' },
|
||||||
|
{ key: 'version', label: 'Version', type: 'string' },
|
||||||
|
{ key: 'status', label: 'Status', type: 'string' },
|
||||||
|
{ key: 'environment', label: 'Environment', type: 'string' },
|
||||||
|
{ key: 'completed_at', label: 'Completed At', type: 'datetime' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
65
searches/find_user.js
Normal file
65
searches/find_user.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Search: Find User
|
||||||
|
* Search for a user by email or ID
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'find_user',
|
||||||
|
noun: 'User',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Find User',
|
||||||
|
description: 'Find a user by email or ID.',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
label: 'Email',
|
||||||
|
type: 'string',
|
||||||
|
helpText: 'Search by email address',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'user_id',
|
||||||
|
label: 'User ID',
|
||||||
|
type: 'string',
|
||||||
|
helpText: 'Search by user ID',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/users/search`,
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
email: bundle.inputData.email,
|
||||||
|
id: bundle.inputData.user_id,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json.users || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'user_abc123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
name: 'Jane Doe',
|
||||||
|
role: 'developer',
|
||||||
|
created_at: '2026-01-01T00:00:00Z',
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'User ID', type: 'string' },
|
||||||
|
{ key: 'email', label: 'Email', type: 'string' },
|
||||||
|
{ key: 'name', label: 'Name', type: 'string' },
|
||||||
|
{ key: 'role', label: 'Role', type: 'string' },
|
||||||
|
{ key: 'created_at', label: 'Created At', type: 'datetime' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
76
triggers/agent_status_change.js
Normal file
76
triggers/agent_status_change.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* Trigger: Agent Status Change
|
||||||
|
* Fires when an AI agent's status changes
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'agent_status_change',
|
||||||
|
noun: 'Agent',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Agent Status Change',
|
||||||
|
description: 'Triggers when an AI agent goes online, offline, or changes status.',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
type: 'polling',
|
||||||
|
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
label: 'New Status',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['all', 'online', 'offline', 'busy', 'error'],
|
||||||
|
default: 'all',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'agent_type',
|
||||||
|
label: 'Agent Type',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['all', 'infrastructure', 'code_review', 'security', 'analytics'],
|
||||||
|
default: 'all',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/webhooks/agents`,
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
status: bundle.inputData.status,
|
||||||
|
type: bundle.inputData.agent_type,
|
||||||
|
since: bundle.meta.isLoadingSample ? undefined : bundle.meta.zap.last_poll,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json.agents || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'agent_roadie_001',
|
||||||
|
name: 'Roadie',
|
||||||
|
type: 'infrastructure',
|
||||||
|
previous_status: 'offline',
|
||||||
|
new_status: 'online',
|
||||||
|
changed_at: '2026-02-15T10:00:00Z',
|
||||||
|
tasks_completed: 42,
|
||||||
|
uptime_percent: 99.9,
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'Agent ID', type: 'string' },
|
||||||
|
{ key: 'name', label: 'Agent Name', type: 'string' },
|
||||||
|
{ key: 'type', label: 'Agent Type', type: 'string' },
|
||||||
|
{ key: 'previous_status', label: 'Previous Status', type: 'string' },
|
||||||
|
{ key: 'new_status', label: 'New Status', type: 'string' },
|
||||||
|
{ key: 'changed_at', label: 'Changed At', type: 'datetime' },
|
||||||
|
{ key: 'tasks_completed', label: 'Tasks Completed', type: 'integer' },
|
||||||
|
{ key: 'uptime_percent', label: 'Uptime %', type: 'number' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
81
triggers/deployment_complete.js
Normal file
81
triggers/deployment_complete.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Trigger: Deployment Complete
|
||||||
|
* Fires when a deployment finishes (success or failure)
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'deployment_complete',
|
||||||
|
noun: 'Deployment',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Deployment Complete',
|
||||||
|
description: 'Triggers when a deployment finishes (success or failure).',
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
type: 'polling',
|
||||||
|
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
label: 'Status Filter',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['all', 'success', 'failure'],
|
||||||
|
default: 'all',
|
||||||
|
helpText: 'Filter by deployment status',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service',
|
||||||
|
label: 'Service',
|
||||||
|
type: 'string',
|
||||||
|
helpText: 'Filter by service name (optional)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/webhooks/deployments`,
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
status: bundle.inputData.status,
|
||||||
|
service: bundle.inputData.service,
|
||||||
|
since: bundle.meta.isLoadingSample ? undefined : bundle.meta.zap.last_poll,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json.deployments || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'deploy_xyz789',
|
||||||
|
service: 'blackroad-api',
|
||||||
|
version: 'v1.2.3',
|
||||||
|
status: 'success',
|
||||||
|
started_at: '2026-02-15T09:55:00Z',
|
||||||
|
completed_at: '2026-02-15T10:00:00Z',
|
||||||
|
duration_seconds: 300,
|
||||||
|
deployed_by: 'user_abc123',
|
||||||
|
environment: 'production',
|
||||||
|
url: 'https://api.blackroad.io',
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'Deployment ID', type: 'string' },
|
||||||
|
{ key: 'service', label: 'Service', type: 'string' },
|
||||||
|
{ key: 'version', label: 'Version', type: 'string' },
|
||||||
|
{ key: 'status', label: 'Status', type: 'string' },
|
||||||
|
{ key: 'started_at', label: 'Started At', type: 'datetime' },
|
||||||
|
{ key: 'completed_at', label: 'Completed At', type: 'datetime' },
|
||||||
|
{ key: 'duration_seconds', label: 'Duration (seconds)', type: 'integer' },
|
||||||
|
{ key: 'deployed_by', label: 'Deployed By', type: 'string' },
|
||||||
|
{ key: 'environment', label: 'Environment', type: 'string' },
|
||||||
|
{ key: 'url', label: 'URL', type: 'string' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
77
triggers/error_occurred.js
Normal file
77
triggers/error_occurred.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* Trigger: Error Occurred
|
||||||
|
* Fires when an error occurs in any BlackRoad service
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'error_occurred',
|
||||||
|
noun: 'Error',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Error Occurred',
|
||||||
|
description: 'Triggers when an error occurs in any BlackRoad service.',
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
type: 'polling',
|
||||||
|
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'severity',
|
||||||
|
label: 'Severity',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['all', 'critical', 'error', 'warning'],
|
||||||
|
default: 'error',
|
||||||
|
helpText: 'Minimum severity level',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service',
|
||||||
|
label: 'Service',
|
||||||
|
type: 'string',
|
||||||
|
helpText: 'Filter by service name (optional)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/webhooks/errors`,
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
severity: bundle.inputData.severity,
|
||||||
|
service: bundle.inputData.service,
|
||||||
|
since: bundle.meta.isLoadingSample ? undefined : bundle.meta.zap.last_poll,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json.errors || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'err_def456',
|
||||||
|
service: 'blackroad-agents',
|
||||||
|
severity: 'error',
|
||||||
|
message: 'Agent connection timeout',
|
||||||
|
code: 'AGENT_TIMEOUT',
|
||||||
|
occurred_at: '2026-02-15T10:00:00Z',
|
||||||
|
resolved: false,
|
||||||
|
affected_users: 12,
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'Error ID', type: 'string' },
|
||||||
|
{ key: 'service', label: 'Service', type: 'string' },
|
||||||
|
{ key: 'severity', label: 'Severity', type: 'string' },
|
||||||
|
{ key: 'message', label: 'Message', type: 'string' },
|
||||||
|
{ key: 'code', label: 'Error Code', type: 'string' },
|
||||||
|
{ key: 'occurred_at', label: 'Occurred At', type: 'datetime' },
|
||||||
|
{ key: 'resolved', label: 'Resolved', type: 'boolean' },
|
||||||
|
{ key: 'affected_users', label: 'Affected Users', type: 'integer' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
66
triggers/new_user.js
Normal file
66
triggers/new_user.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* Trigger: New User Created
|
||||||
|
* Fires when a new user signs up for BlackRoad
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'new_user',
|
||||||
|
noun: 'User',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'New User',
|
||||||
|
description: 'Triggers when a new user signs up for BlackRoad.',
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
type: 'polling',
|
||||||
|
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'product',
|
||||||
|
label: 'Product',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['all', 'vllm', 'api', 'agents', 'dashboard'],
|
||||||
|
default: 'all',
|
||||||
|
helpText: 'Filter by product (optional)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/webhooks/users`,
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
product: bundle.inputData.product,
|
||||||
|
since: bundle.meta.isLoadingSample ? undefined : bundle.meta.zap.last_poll,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json.users || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'user_abc123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
name: 'Jane Doe',
|
||||||
|
created_at: '2026-02-15T10:00:00Z',
|
||||||
|
product: 'vllm',
|
||||||
|
plan: 'pro',
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'User ID', type: 'string' },
|
||||||
|
{ key: 'email', label: 'Email', type: 'string' },
|
||||||
|
{ key: 'name', label: 'Name', type: 'string' },
|
||||||
|
{ key: 'created_at', label: 'Created At', type: 'datetime' },
|
||||||
|
{ key: 'product', label: 'Product', type: 'string' },
|
||||||
|
{ key: 'plan', label: 'Plan', type: 'string' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
74
triggers/usage_threshold.js
Normal file
74
triggers/usage_threshold.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* Trigger: Usage Threshold
|
||||||
|
* Fires when usage exceeds a specified threshold
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://api.blackroad.io';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
key: 'usage_threshold',
|
||||||
|
noun: 'Usage Alert',
|
||||||
|
|
||||||
|
display: {
|
||||||
|
label: 'Usage Threshold Exceeded',
|
||||||
|
description: 'Triggers when usage (API calls, compute, storage) exceeds your threshold.',
|
||||||
|
},
|
||||||
|
|
||||||
|
operation: {
|
||||||
|
type: 'polling',
|
||||||
|
|
||||||
|
inputFields: [
|
||||||
|
{
|
||||||
|
key: 'metric',
|
||||||
|
label: 'Metric',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['api_calls', 'compute_hours', 'storage_gb', 'bandwidth_gb'],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'threshold',
|
||||||
|
label: 'Threshold',
|
||||||
|
type: 'integer',
|
||||||
|
required: true,
|
||||||
|
helpText: 'Alert when usage exceeds this value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
perform: async (z, bundle) => {
|
||||||
|
const response = await z.request({
|
||||||
|
url: `${BASE_URL}/v1/webhooks/usage`,
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
metric: bundle.inputData.metric,
|
||||||
|
threshold: bundle.inputData.threshold,
|
||||||
|
since: bundle.meta.isLoadingSample ? undefined : bundle.meta.zap.last_poll,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${bundle.authData.apiKey}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json.alerts || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
sample: {
|
||||||
|
id: 'alert_usage_001',
|
||||||
|
metric: 'api_calls',
|
||||||
|
threshold: 100000,
|
||||||
|
current_value: 125847,
|
||||||
|
percent_over: 25.8,
|
||||||
|
period: 'monthly',
|
||||||
|
alerted_at: '2026-02-15T10:00:00Z',
|
||||||
|
},
|
||||||
|
|
||||||
|
outputFields: [
|
||||||
|
{ key: 'id', label: 'Alert ID', type: 'string' },
|
||||||
|
{ key: 'metric', label: 'Metric', type: 'string' },
|
||||||
|
{ key: 'threshold', label: 'Threshold', type: 'integer' },
|
||||||
|
{ key: 'current_value', label: 'Current Value', type: 'integer' },
|
||||||
|
{ key: 'percent_over', label: 'Percent Over', type: 'number' },
|
||||||
|
{ key: 'period', label: 'Period', type: 'string' },
|
||||||
|
{ key: 'alerted_at', label: 'Alerted At', type: 'datetime' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user