mirror of
https://github.com/simstudioai/sim.git
synced 2026-03-15 03:00:33 -04:00
Compare commits
6 Commits
v0.5.102
...
feat/short
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb493d94ed | ||
|
|
dd14f9d750 | ||
|
|
fc5e4237ab | ||
|
|
fcefd01f94 | ||
|
|
2408b5af2d | ||
|
|
7327ec0058 |
@@ -76,7 +76,6 @@ export function ApiIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function ConditionalIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
@@ -3998,7 +3997,7 @@ export function LoopsIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 256 256' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fill='#FD4E00'
|
||||
fill='currentColor'
|
||||
d='M192.352 88.042c0-7.012-5.685-12.697-12.697-12.697s-12.697 5.685-12.697 12.697c0 .634.052 1.255.142 1.866a25.248 25.248 0 0 0-4.9-.49c-14.006 0-25.36 11.354-25.36 25.36 0 1.63.16 3.222.456 4.765a37.8 37.8 0 0 0-9.296-1.173c-20.95 0-37.935 16.985-37.935 37.935S107.05 194.24 128 194.24s37.935-16.985 37.935-37.935a37.7 37.7 0 0 0-3.78-16.555 25.2 25.2 0 0 0 12.487-3.336 25.2 25.2 0 0 0 4.558 3.336v.02c14.006 0 25.36-11.354 25.36-25.36 0-12.48-9.018-22.855-20.888-24.996a12.6 12.6 0 0 0 8.68-11.972m-77.05 68.263c0-7.012 5.685-12.697 12.697-12.697s12.697 5.685 12.697 12.697c0 7.013-5.685 12.697-12.697 12.697s-12.697-5.685-12.697-12.697'
|
||||
/>
|
||||
</svg>
|
||||
@@ -4542,7 +4541,7 @@ export function DatabricksIcon(props: SVGProps<SVGSVGElement>) {
|
||||
<svg {...props} viewBox='0 0 241 266' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M228.085 109.654L120.615 171.674L5.53493 105.41L0 108.475V156.582L120.615 225.911L228.085 164.128V189.596L120.615 251.615L5.53493 185.351L0 188.417V196.67L120.615 266L241 196.67V148.564L235.465 145.498L120.615 211.527L12.9148 149.743V124.275L120.615 186.059L241 116.729V69.3298L235.004 65.7925L120.615 131.585L18.4498 73.1028L120.615 14.3848L204.562 62.7269L211.942 58.4823V52.5869L120.615 0L0 69.3298V76.8759L120.615 146.206L228.085 84.1862V109.654Z'
|
||||
fill='#FF3621'
|
||||
fill='#F9F7F4'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
@@ -6012,3 +6011,20 @@ export function HexIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function ShortIoIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 64 65' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect width='64' height='65' fill='#FFFFFF' />
|
||||
<path
|
||||
d='M41.1 45.7c0 2-.8 3.5-2.5 4.6-1.6 1-3.8 1.6-6.5 1.6-3.4 0-6-.8-8-2.3-2-1.6-3-3.6-3.2-6.1l-16.3-.4c0 4.1 1.2 7.8 3.6 11.1A24 24 0 0 0 18 62c2.2 1 4.5 1.7 7 2.2l.4.1H0V.2h24.9A25.4 25.4 0 0 0 9.3 9.5C7.1 12.5 6 15.9 6 19.7c0 4.2.9 7.6 2.6 10.1 1.7 2.5 4 4.4 6.8 5.7 2.8 1.3 6.3 2.3 10.6 3.2 4.4.9 7.5 1.6 9.5 2.2 1.9.5 3.3 1.1 4.3 1.9.8.6 1.3 1.6 1.3 2.9Z'
|
||||
fill='#0BB07D'
|
||||
/>
|
||||
<path d='M25.3 64.2h-.6l.1-.1.5.1Z' fill='#33333D' />
|
||||
<path
|
||||
d='M64 64.2H38.1a28 28 0 0 0 7.1-2.2 23 23 0 0 0 9.4-7.6c2.2-3.2 3.4-6.8 3.4-10.8a17 17 0 0 0-2.6-9.8c-1.7-2.4-4-4.3-6.9-5.5a54.4 54.4 0 0 0-10.8-3.1c-4.3-.8-7.3-1.5-9.2-2.1a12 12 0 0 1-4.2-1.8c-.9-.7-1.3-1.7-1.3-3 0-1.9.7-3.3 2.2-4.3 1.5-1 3.4-1.5 5.8-1.5 2.7 0 4.9.7 6.5 2.1a7.8 7.8 0 0 1 2.7 5.4h16.4c0-3.8-1.1-7.3-3.3-10.5a23 23 0 0 0-9.1-7.4c-2.1-1-4.4-1.7-6.8-2.1H64v64.2Z'
|
||||
fill='#383738'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ import {
|
||||
ServiceNowIcon,
|
||||
SftpIcon,
|
||||
ShopifyIcon,
|
||||
ShortIoIcon,
|
||||
SimilarwebIcon,
|
||||
SlackIcon,
|
||||
SmtpIcon,
|
||||
@@ -283,6 +284,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
sftp: SftpIcon,
|
||||
sharepoint: MicrosoftSharepointIcon,
|
||||
shopify: ShopifyIcon,
|
||||
short_io: ShortIoIcon,
|
||||
similarweb: SimilarwebIcon,
|
||||
slack: SlackIcon,
|
||||
smtp: SmtpIcon,
|
||||
|
||||
@@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="databricks"
|
||||
color="#F9F7F4"
|
||||
color="#FF3621"
|
||||
/>
|
||||
|
||||
{/* MANUAL-CONTENT-START:intro */}
|
||||
|
||||
@@ -35,472 +35,541 @@ Integrate Greenhouse into the workflow. List and retrieve candidates, jobs, appl
|
||||
|
||||
### `greenhouse_list_candidates`
|
||||
|
||||
Lists candidates from Greenhouse with optional filtering by date, job, or email
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `per_page` | number | No | Number of results per page \(1-500, default 100\) |
|
||||
| `page` | number | No | Page number for pagination |
|
||||
| `created_after` | string | No | Return only candidates created at or after this ISO 8601 timestamp |
|
||||
| `created_before` | string | No | Return only candidates created before this ISO 8601 timestamp |
|
||||
| `updated_after` | string | No | Return only candidates updated at or after this ISO 8601 timestamp |
|
||||
| `updated_before` | string | No | Return only candidates updated before this ISO 8601 timestamp |
|
||||
| `job_id` | string | No | Filter to candidates who applied to this job ID \(excludes prospects\) |
|
||||
| `email` | string | No | Filter to candidates with this email address |
|
||||
| `candidate_ids` | string | No | Comma-separated candidate IDs to retrieve \(max 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `candidates` | array | List of candidates |
|
||||
| ↳ `id` | number | Candidate ID |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `company` | string | Current employer |
|
||||
| ↳ `title` | string | Current job title |
|
||||
| ↳ `is_private` | boolean | Whether candidate is private |
|
||||
| ↳ `can_email` | boolean | Whether candidate can be emailed |
|
||||
| ↳ `email_addresses` | array | Email addresses |
|
||||
| ↳ `value` | string | Email address |
|
||||
| ↳ `type` | string | Email type \(personal, work, other\) |
|
||||
| ↳ `tags` | array | Candidate tags |
|
||||
| ↳ `application_ids` | array | Associated application IDs |
|
||||
| ↳ `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| ↳ `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
| ↳ `last_activity` | string | Last activity timestamp \(ISO 8601\) |
|
||||
| `count` | number | Number of candidates returned |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_get_candidate`
|
||||
|
||||
Retrieves a specific candidate by ID with full details including contact info, education, and employment history
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `candidateId` | string | Yes | The ID of the candidate to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | number | Candidate ID |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `company` | string | Current employer |
|
||||
| `title` | string | Current job title |
|
||||
| `is_private` | boolean | Whether candidate is private |
|
||||
| `can_email` | boolean | Whether candidate can be emailed |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
| `last_activity` | string | Last activity timestamp \(ISO 8601\) |
|
||||
| `email_addresses` | array | Email addresses |
|
||||
| ↳ `value` | string | Email address |
|
||||
| ↳ `type` | string | Type \(personal, work, other\) |
|
||||
| `phone_numbers` | array | Phone numbers |
|
||||
| ↳ `value` | string | Phone number |
|
||||
| ↳ `type` | string | Type \(home, work, mobile, skype, other\) |
|
||||
| `addresses` | array | Addresses |
|
||||
| ↳ `value` | string | Address |
|
||||
| ↳ `type` | string | Type \(home, work, other\) |
|
||||
| `website_addresses` | array | Website addresses |
|
||||
| ↳ `value` | string | URL |
|
||||
| ↳ `type` | string | Type \(personal, company, portfolio, blog, other\) |
|
||||
| `social_media_addresses` | array | Social media profiles |
|
||||
| ↳ `value` | string | URL or handle |
|
||||
| `tags` | array | Tags |
|
||||
| `application_ids` | array | Associated application IDs |
|
||||
| `recruiter` | object | Assigned recruiter |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `name` | string | Full name |
|
||||
| ↳ `employee_id` | string | Employee ID |
|
||||
| `coordinator` | object | Assigned coordinator |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `name` | string | Full name |
|
||||
| ↳ `employee_id` | string | Employee ID |
|
||||
| `attachments` | array | File attachments \(URLs expire after 7 days\) |
|
||||
| ↳ `filename` | string | File name |
|
||||
| ↳ `url` | string | Download URL \(expires after 7 days\) |
|
||||
| ↳ `type` | string | Type \(resume, cover_letter, offer_packet, other\) |
|
||||
| ↳ `created_at` | string | Upload timestamp |
|
||||
| `educations` | array | Education history |
|
||||
| ↳ `id` | number | Education record ID |
|
||||
| ↳ `school_name` | string | School name |
|
||||
| ↳ `degree` | string | Degree type |
|
||||
| ↳ `discipline` | string | Field of study |
|
||||
| ↳ `start_date` | string | Start date \(ISO 8601\) |
|
||||
| ↳ `end_date` | string | End date \(ISO 8601\) |
|
||||
| `employments` | array | Employment history |
|
||||
| ↳ `id` | number | Employment record ID |
|
||||
| ↳ `company_name` | string | Company name |
|
||||
| ↳ `title` | string | Job title |
|
||||
| ↳ `start_date` | string | Start date \(ISO 8601\) |
|
||||
| ↳ `end_date` | string | End date \(ISO 8601\) |
|
||||
| `custom_fields` | object | Custom field values |
|
||||
|
||||
### `greenhouse_list_jobs`
|
||||
|
||||
Lists jobs from Greenhouse with optional filtering by status, department, or office
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `per_page` | number | No | Number of results per page \(1-500, default 100\) |
|
||||
| `page` | number | No | Page number for pagination |
|
||||
| `status` | string | No | Filter by job status \(open, closed, draft\) |
|
||||
| `created_after` | string | No | Return only jobs created at or after this ISO 8601 timestamp |
|
||||
| `created_before` | string | No | Return only jobs created before this ISO 8601 timestamp |
|
||||
| `updated_after` | string | No | Return only jobs updated at or after this ISO 8601 timestamp |
|
||||
| `updated_before` | string | No | Return only jobs updated before this ISO 8601 timestamp |
|
||||
| `department_id` | string | No | Filter to jobs in this department ID |
|
||||
| `office_id` | string | No | Filter to jobs in this office ID |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `jobs` | array | List of jobs |
|
||||
| ↳ `id` | number | Job ID |
|
||||
| ↳ `name` | string | Job title |
|
||||
| ↳ `status` | string | Job status \(open, closed, draft\) |
|
||||
| ↳ `confidential` | boolean | Whether the job is confidential |
|
||||
| ↳ `departments` | array | Associated departments |
|
||||
| ↳ `id` | number | Department ID |
|
||||
| ↳ `name` | string | Department name |
|
||||
| ↳ `offices` | array | Associated offices |
|
||||
| ↳ `id` | number | Office ID |
|
||||
| ↳ `name` | string | Office name |
|
||||
| ↳ `opened_at` | string | Date job was opened \(ISO 8601\) |
|
||||
| ↳ `closed_at` | string | Date job was closed \(ISO 8601\) |
|
||||
| ↳ `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| ↳ `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
| `count` | number | Number of jobs returned |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_get_job`
|
||||
|
||||
Retrieves a specific job by ID with full details including hiring team, openings, and custom fields
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `jobId` | string | Yes | The ID of the job to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | number | Job ID |
|
||||
| `name` | string | Job title |
|
||||
| `requisition_id` | string | External requisition ID |
|
||||
| `status` | string | Job status \(open, closed, draft\) |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `opened_at` | string | Date job was opened \(ISO 8601\) |
|
||||
| `closed_at` | string | Date job was closed \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
| `is_template` | boolean | Whether this is a job template |
|
||||
| `notes` | string | Hiring plan notes \(may contain HTML\) |
|
||||
| `departments` | array | Associated departments |
|
||||
| ↳ `id` | number | Department ID |
|
||||
| ↳ `name` | string | Department name |
|
||||
| ↳ `parent_id` | number | Parent department ID |
|
||||
| `offices` | array | Associated offices |
|
||||
| ↳ `id` | number | Office ID |
|
||||
| ↳ `name` | string | Office name |
|
||||
| ↳ `location` | object | Office location |
|
||||
| ↳ `name` | string | Location name |
|
||||
| `hiring_team` | object | Hiring team members |
|
||||
| ↳ `hiring_managers` | array | Hiring managers |
|
||||
| ↳ `recruiters` | array | Recruiters \(includes responsible flag\) |
|
||||
| ↳ `coordinators` | array | Coordinators \(includes responsible flag\) |
|
||||
| ↳ `sourcers` | array | Sourcers |
|
||||
| `openings` | array | Job openings/slots |
|
||||
| ↳ `id` | number | Opening internal ID |
|
||||
| ↳ `opening_id` | string | Custom opening identifier |
|
||||
| ↳ `status` | string | Opening status \(open, closed\) |
|
||||
| ↳ `opened_at` | string | Date opened \(ISO 8601\) |
|
||||
| ↳ `closed_at` | string | Date closed \(ISO 8601\) |
|
||||
| ↳ `application_id` | number | Hired application ID |
|
||||
| ↳ `close_reason` | object | Reason for closing |
|
||||
| ↳ `id` | number | Close reason ID |
|
||||
| ↳ `name` | string | Close reason name |
|
||||
| `custom_fields` | object | Custom field values |
|
||||
|
||||
### `greenhouse_list_applications`
|
||||
|
||||
Lists applications from Greenhouse with optional filtering by job, status, or date
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `per_page` | number | No | Number of results per page \(1-500, default 100\) |
|
||||
| `page` | number | No | Page number for pagination |
|
||||
| `job_id` | string | No | Filter applications by job ID |
|
||||
| `status` | string | No | Filter by status \(active, converted, hired, rejected\) |
|
||||
| `created_after` | string | No | Return only applications created at or after this ISO 8601 timestamp |
|
||||
| `created_before` | string | No | Return only applications created before this ISO 8601 timestamp |
|
||||
| `last_activity_after` | string | No | Return only applications with activity at or after this ISO 8601 timestamp |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `applications` | array | List of applications |
|
||||
| ↳ `id` | number | Application ID |
|
||||
| ↳ `candidate_id` | number | Associated candidate ID |
|
||||
| ↳ `prospect` | boolean | Whether this is a prospect application |
|
||||
| ↳ `status` | string | Status \(active, converted, hired, rejected\) |
|
||||
| ↳ `current_stage` | object | Current interview stage |
|
||||
| ↳ `id` | number | Stage ID |
|
||||
| ↳ `name` | string | Stage name |
|
||||
| ↳ `jobs` | array | Associated jobs |
|
||||
| ↳ `id` | number | Job ID |
|
||||
| ↳ `name` | string | Job name |
|
||||
| ↳ `applied_at` | string | Application date \(ISO 8601\) |
|
||||
| ↳ `rejected_at` | string | Rejection date \(ISO 8601\) |
|
||||
| ↳ `last_activity_at` | string | Last activity date \(ISO 8601\) |
|
||||
| `count` | number | Number of applications returned |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_get_application`
|
||||
|
||||
Retrieves a specific application by ID with full details including source, stage, answers, and attachments
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `applicationId` | string | Yes | The ID of the application to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | number | Application ID |
|
||||
| `candidate_id` | number | Associated candidate ID |
|
||||
| `prospect` | boolean | Whether this is a prospect application |
|
||||
| `status` | string | Status \(active, converted, hired, rejected\) |
|
||||
| `applied_at` | string | Application date \(ISO 8601\) |
|
||||
| `rejected_at` | string | Rejection date \(ISO 8601\) |
|
||||
| `last_activity_at` | string | Last activity date \(ISO 8601\) |
|
||||
| `location` | object | Candidate location |
|
||||
| ↳ `address` | string | Location address |
|
||||
| `source` | object | Application source |
|
||||
| ↳ `id` | number | Source ID |
|
||||
| ↳ `public_name` | string | Source name |
|
||||
| `credited_to` | object | User credited for the application |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `name` | string | Full name |
|
||||
| ↳ `employee_id` | string | Employee ID |
|
||||
| `recruiter` | object | Assigned recruiter |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `name` | string | Full name |
|
||||
| ↳ `employee_id` | string | Employee ID |
|
||||
| `coordinator` | object | Assigned coordinator |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `name` | string | Full name |
|
||||
| ↳ `employee_id` | string | Employee ID |
|
||||
| `current_stage` | object | Current interview stage \(null when hired\) |
|
||||
| ↳ `id` | number | Stage ID |
|
||||
| ↳ `name` | string | Stage name |
|
||||
| `rejection_reason` | object | Rejection reason |
|
||||
| ↳ `id` | number | Rejection reason ID |
|
||||
| ↳ `name` | string | Rejection reason name |
|
||||
| ↳ `type` | object | Rejection reason type |
|
||||
| ↳ `id` | number | Type ID |
|
||||
| ↳ `name` | string | Type name |
|
||||
| `jobs` | array | Associated jobs |
|
||||
| ↳ `id` | number | Job ID |
|
||||
| ↳ `name` | string | Job name |
|
||||
| `job_post_id` | number | Job post ID |
|
||||
| `answers` | array | Application question answers |
|
||||
| ↳ `question` | string | Question text |
|
||||
| ↳ `answer` | string | Answer text |
|
||||
| `attachments` | array | File attachments \(URLs expire after 7 days\) |
|
||||
| ↳ `filename` | string | File name |
|
||||
| ↳ `url` | string | Download URL \(expires after 7 days\) |
|
||||
| ↳ `type` | string | Type \(resume, cover_letter, offer_packet, other\) |
|
||||
| ↳ `created_at` | string | Upload timestamp |
|
||||
| `custom_fields` | object | Custom field values |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_list_users`
|
||||
|
||||
Lists Greenhouse users (recruiters, hiring managers, admins) with optional filtering
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `per_page` | number | No | Number of results per page \(1-500, default 100\) |
|
||||
| `page` | number | No | Page number for pagination |
|
||||
| `created_after` | string | No | Return only users created at or after this ISO 8601 timestamp |
|
||||
| `created_before` | string | No | Return only users created before this ISO 8601 timestamp |
|
||||
| `updated_after` | string | No | Return only users updated at or after this ISO 8601 timestamp |
|
||||
| `updated_before` | string | No | Return only users updated before this ISO 8601 timestamp |
|
||||
| `email` | string | No | Filter by email address |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `users` | array | List of Greenhouse users |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `name` | string | Full name |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `primary_email_address` | string | Primary email |
|
||||
| ↳ `disabled` | boolean | Whether the user is disabled |
|
||||
| ↳ `site_admin` | boolean | Whether the user is a site admin |
|
||||
| ↳ `emails` | array | All email addresses |
|
||||
| ↳ `employee_id` | string | Employee ID |
|
||||
| ↳ `linked_candidate_ids` | array | IDs of candidates linked to this user |
|
||||
| ↳ `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| ↳ `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
| `count` | number | Number of users returned |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_get_user`
|
||||
|
||||
Retrieves a specific Greenhouse user by ID
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `userId` | string | Yes | The ID of the user to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | number | User ID |
|
||||
| `name` | string | Full name |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `emails` | array | All email addresses |
|
||||
| `employee_id` | string | Employee ID |
|
||||
| `linked_candidate_ids` | array | IDs of candidates linked to this user |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_list_departments`
|
||||
|
||||
Lists all departments configured in Greenhouse
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `per_page` | number | No | Number of results per page \(1-500, default 100\) |
|
||||
| `page` | number | No | Page number for pagination |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `departments` | array | List of departments |
|
||||
| ↳ `id` | number | Department ID |
|
||||
| ↳ `name` | string | Department name |
|
||||
| ↳ `parent_id` | number | Parent department ID |
|
||||
| ↳ `child_ids` | array | Child department IDs |
|
||||
| ↳ `external_id` | string | External system ID |
|
||||
| `count` | number | Number of departments returned |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_list_offices`
|
||||
|
||||
Lists all offices configured in Greenhouse
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `per_page` | number | No | Number of results per page \(1-500, default 100\) |
|
||||
| `page` | number | No | Page number for pagination |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `offices` | array | List of offices |
|
||||
| ↳ `id` | number | Office ID |
|
||||
| ↳ `name` | string | Office name |
|
||||
| ↳ `location` | object | Office location |
|
||||
| ↳ `name` | string | Location name |
|
||||
| ↳ `primary_contact_user_id` | number | Primary contact user ID |
|
||||
| ↳ `parent_id` | number | Parent office ID |
|
||||
| ↳ `child_ids` | array | Child office IDs |
|
||||
| ↳ `external_id` | string | External system ID |
|
||||
| `count` | number | Number of offices returned |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
### `greenhouse_list_job_stages`
|
||||
|
||||
Lists all interview stages for a specific job in Greenhouse
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Greenhouse Harvest API key |
|
||||
| `jobId` | string | Yes | The job ID to list stages for |
|
||||
| `per_page` | number | No | Number of results per page \(1-500, default 100\) |
|
||||
| `page` | number | No | Page number for pagination |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `stages` | array | List of job stages in order |
|
||||
| ↳ `id` | number | Stage ID |
|
||||
| ↳ `name` | string | Stage name |
|
||||
| ↳ `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| ↳ `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
| ↳ `job_id` | number | Associated job ID |
|
||||
| ↳ `priority` | number | Stage order priority |
|
||||
| ↳ `active` | boolean | Whether the stage is active |
|
||||
| ↳ `interviews` | array | Interview steps in this stage |
|
||||
| ↳ `id` | number | Interview ID |
|
||||
| ↳ `name` | string | Interview name |
|
||||
| ↳ `schedulable` | boolean | Whether the interview is schedulable |
|
||||
| ↳ `estimated_minutes` | number | Estimated duration in minutes |
|
||||
| ↳ `default_interviewer_users` | array | Default interviewers |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `name` | string | Full name |
|
||||
| ↳ `first_name` | string | First name |
|
||||
| ↳ `last_name` | string | Last name |
|
||||
| ↳ `employee_id` | string | Employee ID |
|
||||
| ↳ `interview_kit` | object | Interview kit details |
|
||||
| ↳ `id` | number | Kit ID |
|
||||
| ↳ `content` | string | Kit content \(HTML\) |
|
||||
| ↳ `questions` | array | Interview kit questions |
|
||||
| ↳ `id` | number | Question ID |
|
||||
| ↳ `question` | string | Question text |
|
||||
| `count` | number | Number of stages returned |
|
||||
| `candidates` | json | List of candidates |
|
||||
| `jobs` | json | List of jobs |
|
||||
| `applications` | json | List of applications |
|
||||
| `users` | json | List of users |
|
||||
| `departments` | json | List of departments |
|
||||
| `offices` | json | List of offices |
|
||||
| `stages` | json | List of job stages |
|
||||
| `count` | number | Number of results returned |
|
||||
| `id` | number | Resource ID |
|
||||
| `first_name` | string | First name |
|
||||
| `last_name` | string | Last name |
|
||||
| `name` | string | Resource name |
|
||||
| `status` | string | Status |
|
||||
| `email_addresses` | json | Email addresses |
|
||||
| `phone_numbers` | json | Phone numbers |
|
||||
| `tags` | json | Tags |
|
||||
| `application_ids` | json | Associated application IDs |
|
||||
| `recruiter` | json | Assigned recruiter |
|
||||
| `coordinator` | json | Assigned coordinator |
|
||||
| `current_stage` | json | Current interview stage |
|
||||
| `source` | json | Application source |
|
||||
| `hiring_team` | json | Hiring team members |
|
||||
| `openings` | json | Job openings |
|
||||
| `custom_fields` | json | Custom field values |
|
||||
| `attachments` | json | File attachments |
|
||||
| `educations` | json | Education history |
|
||||
| `employments` | json | Employment history |
|
||||
| `answers` | json | Application question answers |
|
||||
| `prospect` | boolean | Whether this is a prospect |
|
||||
| `confidential` | boolean | Whether the job is confidential |
|
||||
| `is_private` | boolean | Whether the candidate is private |
|
||||
| `can_email` | boolean | Whether the candidate can be emailed |
|
||||
| `disabled` | boolean | Whether the user is disabled |
|
||||
| `site_admin` | boolean | Whether the user is a site admin |
|
||||
| `primary_email_address` | string | Primary email address |
|
||||
| `created_at` | string | Creation timestamp \(ISO 8601\) |
|
||||
| `updated_at` | string | Last updated timestamp \(ISO 8601\) |
|
||||
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
"sftp",
|
||||
"sharepoint",
|
||||
"shopify",
|
||||
"short_io",
|
||||
"similarweb",
|
||||
"slack",
|
||||
"smtp",
|
||||
|
||||
173
apps/docs/content/docs/en/tools/short_io.mdx
Normal file
173
apps/docs/content/docs/en/tools/short_io.mdx
Normal file
@@ -0,0 +1,173 @@
|
||||
---
|
||||
title: Short.io
|
||||
description: Create and manage short links, domains, and analytics.
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="short_io"
|
||||
color="#FFFFFF"
|
||||
/>
|
||||
|
||||
{/* MANUAL-CONTENT-START:intro */}
|
||||
[Short.io](https://short.io/) is a white-label URL shortener that lets you create branded short links on your own domain, track clicks, and manage links at scale. Short.io is designed for businesses that want professional short URLs, QR codes, and link analytics without relying on generic shorteners.
|
||||
|
||||
With Short.io in Sim, you can:
|
||||
|
||||
- **Create short links**: Generate branded short URLs from long URLs using your custom domain, with optional custom paths
|
||||
- **List domains**: Retrieve all Short.io domains on your account to get domain IDs for listing links
|
||||
- **List links**: List short links for a domain with pagination and optional date sort order
|
||||
- **Delete links**: Remove a short link by its ID (e.g. lnk_abc123_abcdef)
|
||||
- **Generate QR codes**: Create QR codes for any Short.io link with optional size, color, background color, and format (PNG or SVG); returns a base64 data URL
|
||||
- **Get link statistics**: Fetch click analytics for a link including total clicks, human clicks, referrer/country/browser/OS/city breakdowns, UTM dimensions, time-series data, and date interval
|
||||
|
||||
These capabilities allow your Sim agents to automate link shortening, QR code generation, and analytics reporting directly in your workflows — from campaign tracking to link management and performance dashboards.
|
||||
{/* MANUAL-CONTENT-END */}
|
||||
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate Short.io to generate branded short links, list domains and links, delete links, generate QR codes, and view link statistics. Requires your Short.io Secret API Key.
|
||||
|
||||
|
||||
|
||||
## Tools
|
||||
|
||||
### `short_io_create_link`
|
||||
|
||||
Create a short link using your Short.io custom domain.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Short.io Secret API Key |
|
||||
| `domain` | string | Yes | Your registered Short.io custom domain |
|
||||
| `originalURL` | string | Yes | The long URL to shorten |
|
||||
| `path` | string | No | Optional custom path for the short link |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `shortURL` | string | The generated short link URL |
|
||||
| `idString` | string | The unique Short.io link ID string |
|
||||
| `originalURL` | string | The original long URL |
|
||||
| `path` | string | The path/slug of the short link |
|
||||
| `createdAt` | string | ISO 8601 creation timestamp |
|
||||
|
||||
### `short_io_list_domains`
|
||||
|
||||
List Short.io domains. Returns domain IDs and details for use in List Links.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Short.io Secret API Key |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `domains` | array | List of domain objects \(id, hostname, etc.\) |
|
||||
| `count` | number | Number of domains |
|
||||
|
||||
### `short_io_list_links`
|
||||
|
||||
List short links for a domain. Requires domain_id (from List Domains or dashboard). Max 150 per request.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Short.io Secret API Key |
|
||||
| `domainId` | number | Yes | Domain ID \(from List Domains\) |
|
||||
| `limit` | number | No | Max links to return \(1–150\) |
|
||||
| `pageToken` | string | No | Pagination token from previous response |
|
||||
| `dateSortOrder` | string | No | Sort by date: asc or desc |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `links` | array | List of link objects \(idString, shortURL, originalURL, path, etc.\) |
|
||||
| `count` | number | Number of links returned |
|
||||
| `nextPageToken` | string | Token for next page |
|
||||
|
||||
### `short_io_delete_link`
|
||||
|
||||
Delete a short link by ID (e.g. lnk_abc123_abcdef). Rate limit 20/s.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Short.io Secret API Key |
|
||||
| `linkId` | string | Yes | Link ID to delete |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether the link was deleted |
|
||||
| `idString` | string | Deleted link ID |
|
||||
|
||||
### `short_io_get_qr_code`
|
||||
|
||||
Generate a QR code for a Short.io link (POST /links/qr/{linkIdString}).
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Short.io Secret API Key |
|
||||
| `linkId` | string | Yes | Link ID \(e.g. lnk_abc123_abcdef\) |
|
||||
| `color` | string | No | QR color hex \(e.g. 000000\) |
|
||||
| `backgroundColor` | string | No | Background color hex \(e.g. FFFFFF\) |
|
||||
| `size` | number | No | QR size 1–99 |
|
||||
| `type` | string | No | Output format: png or svg |
|
||||
| `useDomainSettings` | boolean | No | Use domain settings \(default true\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `file` | file | Generated QR code image file |
|
||||
|
||||
### `short_io_get_analytics`
|
||||
|
||||
Fetch click statistics for a Short.io link (Statistics API: totalClicks, humanClicks, referer, country, etc.).
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Short.io Secret API Key |
|
||||
| `linkId` | string | Yes | No description |
|
||||
| `period` | string | Yes | Period: today, yesterday, last7, last30, total, week, month, lastmonth |
|
||||
| `tz` | string | No | Timezone \(default UTC\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `totalClicks` | number | Total clicks |
|
||||
| `humanClicks` | number | Human clicks |
|
||||
| `totalClicksChange` | string | Change vs previous period |
|
||||
| `humanClicksChange` | string | Human clicks change |
|
||||
| `referer` | array | Referrer breakdown \(referer, score\) |
|
||||
| `country` | array | Country breakdown \(countryName, country, score\) |
|
||||
| `browser` | array | Browser breakdown \(browser, score\) |
|
||||
| `os` | array | OS breakdown \(os, score\) |
|
||||
| `city` | array | City breakdown \(city, name, countryCode, score\) |
|
||||
| `device` | array | Device breakdown |
|
||||
| `social` | array | Social source breakdown \(social, score\) |
|
||||
| `utmMedium` | array | UTM medium breakdown |
|
||||
| `utmSource` | array | UTM source breakdown |
|
||||
| `utmCampaign` | array | UTM campaign breakdown |
|
||||
| `clickStatistics` | object | Time-series click data \(datasets with x/y points per interval\) |
|
||||
| `interval` | object | Date range \(startDate, endDate, prevStartDate, prevEndDate, tz\) |
|
||||
|
||||
|
||||
101
apps/sim/app/api/tools/short_io/qr/route.ts
Normal file
101
apps/sim/app/api/tools/short_io/qr/route.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('ShortIoQrAPI')
|
||||
|
||||
const ShortIoQrSchema = z.object({
|
||||
apiKey: z.string().min(1, 'API key is required'),
|
||||
linkId: z.string().min(1, 'Link ID is required'),
|
||||
color: z.string().optional(),
|
||||
backgroundColor: z.string().optional(),
|
||||
size: z.number().min(1).max(99).optional(),
|
||||
type: z.enum(['png', 'svg']).optional(),
|
||||
useDomainSettings: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
try {
|
||||
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
|
||||
|
||||
if (!authResult.success) {
|
||||
logger.warn(`[${requestId}] Unauthorized Short.io QR request: ${authResult.error}`)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: authResult.error || 'Authentication required' },
|
||||
{ status: 401 }
|
||||
)
|
||||
}
|
||||
|
||||
const body = await request.json()
|
||||
const validated = ShortIoQrSchema.parse(body)
|
||||
|
||||
const qrBody: Record<string, unknown> = {
|
||||
useDomainSettings: validated.useDomainSettings ?? true,
|
||||
}
|
||||
if (validated.color) qrBody.color = validated.color
|
||||
if (validated.backgroundColor) qrBody.backgroundColor = validated.backgroundColor
|
||||
if (validated.size) qrBody.size = validated.size
|
||||
if (validated.type) qrBody.type = validated.type
|
||||
|
||||
const response = await fetch(`https://api.short.io/links/qr/${validated.linkId}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: validated.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(qrBody),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text().catch(() => response.statusText)
|
||||
logger.error(`[${requestId}] Short.io QR API error: ${errorText}`)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: `Short.io API error: ${errorText}` },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const contentType = response.headers.get('Content-Type') ?? 'image/png'
|
||||
const fileBuffer = Buffer.from(await response.arrayBuffer())
|
||||
const mimeType = contentType.split(';')[0]?.trim() || 'image/png'
|
||||
const ext = validated.type === 'svg' ? 'svg' : 'png'
|
||||
const fileName = `qr-${validated.linkId}.${ext}`
|
||||
|
||||
logger.info(`[${requestId}] QR code generated`, {
|
||||
linkId: validated.linkId,
|
||||
size: fileBuffer.length,
|
||||
mimeType,
|
||||
})
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
file: {
|
||||
name: fileName,
|
||||
mimeType,
|
||||
data: fileBuffer.toString('base64'),
|
||||
size: fileBuffer.length,
|
||||
},
|
||||
},
|
||||
})
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: `Validation error: ${error.errors.map((e) => e.message).join(', ')}`,
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
logger.error(`[${requestId}] Short.io QR error: ${message}`)
|
||||
return NextResponse.json({ success: false, error: message }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,7 @@ export function ChatDeploy({
|
||||
onVersionActivated,
|
||||
}: ChatDeployProps) {
|
||||
const [imageUrl, setImageUrl] = useState<string | null>(null)
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
const [internalShowDeleteConfirmation, setInternalShowDeleteConfirmation] = useState(false)
|
||||
|
||||
const showDeleteConfirmation =
|
||||
@@ -121,7 +122,6 @@ export function ChatDeploy({
|
||||
const [formData, setFormData] = useState<ChatFormData>(initialFormData)
|
||||
const [errors, setErrors] = useState<FormErrors>({})
|
||||
const formRef = useRef<HTMLFormElement>(null)
|
||||
const [formInitCounter, setFormInitCounter] = useState(0)
|
||||
|
||||
const createChatMutation = useCreateChat()
|
||||
const updateChatMutation = useUpdateChat()
|
||||
@@ -222,20 +222,13 @@ export function ChatDeploy({
|
||||
|
||||
setChatSubmitting(true)
|
||||
|
||||
const isNewChat = !existingChat?.id
|
||||
|
||||
// Open window before async operation to avoid popup blockers
|
||||
const newTab = isNewChat ? window.open('', '_blank') : null
|
||||
|
||||
try {
|
||||
if (!validateForm(!!existingChat)) {
|
||||
newTab?.close()
|
||||
setChatSubmitting(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (!isIdentifierValid && formData.identifier !== existingChat?.identifier) {
|
||||
newTab?.close()
|
||||
setError('identifier', 'Please wait for identifier validation to complete')
|
||||
setChatSubmitting(false)
|
||||
return
|
||||
@@ -264,18 +257,13 @@ export function ChatDeploy({
|
||||
onDeployed?.()
|
||||
onVersionActivated?.()
|
||||
|
||||
if (newTab && chatUrl) {
|
||||
newTab.opener = null
|
||||
newTab.location.href = chatUrl
|
||||
} else if (newTab) {
|
||||
newTab.close()
|
||||
if (chatUrl) {
|
||||
window.open(chatUrl, '_blank', 'noopener,noreferrer')
|
||||
}
|
||||
|
||||
await onRefetchChat()
|
||||
setHasInitializedForm(false)
|
||||
setFormInitCounter((c) => c + 1)
|
||||
await onRefetchChat()
|
||||
} catch (error: any) {
|
||||
newTab?.close()
|
||||
if (error.message?.includes('identifier')) {
|
||||
setError('identifier', error.message)
|
||||
} else {
|
||||
@@ -290,6 +278,8 @@ export function ChatDeploy({
|
||||
if (!existingChat || !existingChat.id) return
|
||||
|
||||
try {
|
||||
setIsDeleting(true)
|
||||
|
||||
await deleteChatMutation.mutateAsync({
|
||||
chatId: existingChat.id,
|
||||
workflowId,
|
||||
@@ -297,7 +287,6 @@ export function ChatDeploy({
|
||||
|
||||
setImageUrl(null)
|
||||
setHasInitializedForm(false)
|
||||
setFormInitCounter((c) => c + 1)
|
||||
await onRefetchChat()
|
||||
|
||||
onDeploymentComplete?.()
|
||||
@@ -305,6 +294,7 @@ export function ChatDeploy({
|
||||
logger.error('Failed to delete chat:', error)
|
||||
setError('general', error.message || 'An unexpected error occurred while deleting')
|
||||
} finally {
|
||||
setIsDeleting(false)
|
||||
setShowDeleteConfirmation(false)
|
||||
}
|
||||
}
|
||||
@@ -373,7 +363,7 @@ export function ChatDeploy({
|
||||
</div>
|
||||
|
||||
<AuthSelector
|
||||
key={`${existingChat?.id ?? 'new'}-${formInitCounter}`}
|
||||
key={existingChat?.id ?? 'new'}
|
||||
authType={formData.authType}
|
||||
password={formData.password}
|
||||
emails={formData.emails}
|
||||
@@ -434,16 +424,12 @@ export function ChatDeploy({
|
||||
<Button
|
||||
variant='default'
|
||||
onClick={() => setShowDeleteConfirmation(false)}
|
||||
disabled={deleteChatMutation.isPending}
|
||||
disabled={isDeleting}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant='destructive'
|
||||
onClick={handleDelete}
|
||||
disabled={deleteChatMutation.isPending}
|
||||
>
|
||||
{deleteChatMutation.isPending ? 'Deleting...' : 'Delete'}
|
||||
<Button variant='destructive' onClick={handleDelete} disabled={isDeleting}>
|
||||
{isDeleting ? 'Deleting...' : 'Delete'}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
@@ -634,12 +620,6 @@ function AuthSelector({
|
||||
emails.map((email) => ({ value: email, isValid: true }))
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!copySuccess) return
|
||||
const timer = setTimeout(() => setCopySuccess(false), 2000)
|
||||
return () => clearTimeout(timer)
|
||||
}, [copySuccess])
|
||||
|
||||
const handleGeneratePassword = () => {
|
||||
const newPassword = generatePassword(24)
|
||||
onPasswordChange(newPassword)
|
||||
@@ -648,6 +628,7 @@ function AuthSelector({
|
||||
const copyToClipboard = (text: string) => {
|
||||
navigator.clipboard.writeText(text)
|
||||
setCopySuccess(true)
|
||||
setTimeout(() => setCopySuccess(false), 2000)
|
||||
}
|
||||
|
||||
const addEmail = (email: string): boolean => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import {
|
||||
@@ -113,7 +113,6 @@ export function DeployModal({
|
||||
const [showA2aDeleteConfirm, setShowA2aDeleteConfirm] = useState(false)
|
||||
|
||||
const [chatSuccess, setChatSuccess] = useState(false)
|
||||
const chatSuccessTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
const [isCreateKeyModalOpen, setIsCreateKeyModalOpen] = useState(false)
|
||||
const [isApiInfoModalOpen, setIsApiInfoModalOpen] = useState(false)
|
||||
@@ -233,12 +232,6 @@ export function DeployModal({
|
||||
setActiveTab('general')
|
||||
setDeployError(null)
|
||||
setDeployWarnings([])
|
||||
setChatSuccess(false)
|
||||
}
|
||||
return () => {
|
||||
if (chatSuccessTimeoutRef.current) {
|
||||
clearTimeout(chatSuccessTimeoutRef.current)
|
||||
}
|
||||
}
|
||||
}, [open, workflowId])
|
||||
|
||||
@@ -384,16 +377,15 @@ export function DeployModal({
|
||||
const handleChatDeployed = useCallback(async () => {
|
||||
if (!workflowId) return
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.info(workflowId) })
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.versions(workflowId) })
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.chatStatus(workflowId) })
|
||||
|
||||
await refetchDeployedState()
|
||||
useWorkflowRegistry.getState().setWorkflowNeedsRedeployment(workflowId, false)
|
||||
|
||||
if (chatSuccessTimeoutRef.current) {
|
||||
clearTimeout(chatSuccessTimeoutRef.current)
|
||||
}
|
||||
setChatSuccess(true)
|
||||
chatSuccessTimeoutRef.current = setTimeout(() => setChatSuccess(false), 2000)
|
||||
setTimeout(() => setChatSuccess(false), 2000)
|
||||
}, [workflowId, queryClient, refetchDeployedState])
|
||||
|
||||
const handleRefetchChat = useCallback(async () => {
|
||||
@@ -402,7 +394,14 @@ export function DeployModal({
|
||||
|
||||
const handleChatFormSubmit = useCallback(() => {
|
||||
const form = document.getElementById('chat-deploy-form') as HTMLFormElement
|
||||
form?.requestSubmit()
|
||||
if (form) {
|
||||
const updateTrigger = form.querySelector('[data-update-trigger]') as HTMLButtonElement
|
||||
if (updateTrigger) {
|
||||
updateTrigger.click()
|
||||
} else {
|
||||
form.requestSubmit()
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleChatDelete = useCallback(() => {
|
||||
|
||||
@@ -12,7 +12,7 @@ export const DatabricksBlock: BlockConfig<DatabricksResponse> = {
|
||||
'Connect to Databricks to execute SQL queries against SQL warehouses, trigger and monitor job runs, manage clusters, and retrieve run outputs. Requires a Personal Access Token and workspace host URL.',
|
||||
docsLink: 'https://docs.sim.ai/tools/databricks',
|
||||
category: 'tools',
|
||||
bgColor: '#F9F7F4',
|
||||
bgColor: '#FF3621',
|
||||
icon: DatabricksIcon,
|
||||
subBlocks: [
|
||||
{
|
||||
|
||||
@@ -154,9 +154,7 @@ Example:
|
||||
{
|
||||
"clxf1nxlb000t0ml79ajwcsj0": true,
|
||||
"clxf2q43u00010mlh12q9ggx1": false
|
||||
}
|
||||
|
||||
Return ONLY the JSON object - no explanations, no extra text.`,
|
||||
}`,
|
||||
placeholder: 'Describe the mailing list subscriptions...',
|
||||
},
|
||||
},
|
||||
@@ -185,9 +183,7 @@ Example:
|
||||
"signupDate": "2024-01-15T00:00:00Z",
|
||||
"isActive": true,
|
||||
"seats": 5
|
||||
}
|
||||
|
||||
Return ONLY the JSON object - no explanations, no extra text.`,
|
||||
}`,
|
||||
placeholder: 'Describe the custom properties...',
|
||||
},
|
||||
},
|
||||
@@ -225,9 +221,7 @@ Example:
|
||||
"name": "John Smith",
|
||||
"confirmationUrl": "https://example.com/confirm?token=abc123",
|
||||
"expiresIn": 24
|
||||
}
|
||||
|
||||
Return ONLY the JSON object - no explanations, no extra text.`,
|
||||
}`,
|
||||
placeholder: 'Describe the template variables...',
|
||||
},
|
||||
},
|
||||
@@ -267,9 +261,7 @@ Example:
|
||||
"contentType": "application/pdf",
|
||||
"data": "JVBERi0xLjQK..."
|
||||
}
|
||||
]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no extra text.`,
|
||||
]`,
|
||||
placeholder: 'Describe the attachments...',
|
||||
},
|
||||
},
|
||||
@@ -308,9 +300,7 @@ Example:
|
||||
"amount": 49.99,
|
||||
"currency": "USD",
|
||||
"isUpgrade": true
|
||||
}
|
||||
|
||||
Return ONLY the JSON object - no explanations, no extra text.`,
|
||||
}`,
|
||||
placeholder: 'Describe the event properties...',
|
||||
},
|
||||
},
|
||||
@@ -359,7 +349,6 @@ Return ONLY the JSON object - no explanations, no extra text.`,
|
||||
{ label: 'Boolean', id: 'boolean' },
|
||||
{ label: 'Date', id: 'date' },
|
||||
],
|
||||
value: () => 'string',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_contact_property',
|
||||
@@ -374,7 +363,6 @@ Return ONLY the JSON object - no explanations, no extra text.`,
|
||||
{ label: 'All Properties', id: 'all' },
|
||||
{ label: 'Custom Only', id: 'custom' },
|
||||
],
|
||||
value: () => 'all',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'list_contact_properties',
|
||||
@@ -509,28 +497,23 @@ Return ONLY the JSON object - no explanations, no extra text.`,
|
||||
outputs: {
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
id: { type: 'string', description: 'Contact ID (create/update operations)' },
|
||||
contacts: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Array of matching contacts (id, email, firstName, lastName, source, subscribed, userGroup, userId, mailingLists, optInStatus)',
|
||||
},
|
||||
contacts: { type: 'json', description: 'Array of matching contacts (find operation)' },
|
||||
message: { type: 'string', description: 'Status message (delete operation)' },
|
||||
mailingLists: {
|
||||
type: 'json',
|
||||
description: 'Array of mailing lists (id, name, description, isPublic)',
|
||||
description: 'Array of mailing lists (list mailing lists operation)',
|
||||
},
|
||||
transactionalEmails: {
|
||||
type: 'json',
|
||||
description: 'Array of transactional email templates (id, name, lastUpdated, dataVariables)',
|
||||
description: 'Array of transactional email templates (list transactional emails operation)',
|
||||
},
|
||||
pagination: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Pagination info (totalResults, returnedResults, perPage, totalPages, nextCursor, nextPage)',
|
||||
description: 'Pagination info (list transactional emails operation)',
|
||||
},
|
||||
properties: {
|
||||
type: 'json',
|
||||
description: 'Array of contact properties (key, label, type)',
|
||||
description: 'Array of contact properties (list contact properties operation)',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
272
apps/sim/blocks/blocks/short_io.ts
Normal file
272
apps/sim/blocks/blocks/short_io.ts
Normal file
@@ -0,0 +1,272 @@
|
||||
import { ShortIoIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
export const ShortIoBlock: BlockConfig<ToolResponse> = {
|
||||
type: 'short_io',
|
||||
name: 'Short.io',
|
||||
description: 'Create and manage short links, domains, and analytics.',
|
||||
authMode: AuthMode.ApiKey,
|
||||
longDescription:
|
||||
'Integrate Short.io to generate branded short links, list domains and links, delete links, generate QR codes, and view link statistics. Requires your Short.io Secret API Key.',
|
||||
docsLink: 'https://docs.sim.ai/tools/short_io',
|
||||
category: 'tools',
|
||||
bgColor: '#FFFFFF',
|
||||
icon: ShortIoIcon,
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Create Link', id: 'create_link' },
|
||||
{ label: 'List Domains', id: 'list_domains' },
|
||||
{ label: 'List Links', id: 'list_links' },
|
||||
{ label: 'Delete Link', id: 'delete_link' },
|
||||
{ label: 'Get QR Code', id: 'get_qr_code' },
|
||||
{ label: 'Get Link Statistics', id: 'get_analytics' },
|
||||
],
|
||||
value: () => 'create_link',
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'Secret API Key',
|
||||
type: 'short-input',
|
||||
mode: 'basic',
|
||||
required: true,
|
||||
password: true,
|
||||
placeholder: 'sk_...',
|
||||
},
|
||||
{
|
||||
id: 'domain',
|
||||
title: 'Custom Domain',
|
||||
type: 'short-input',
|
||||
placeholder: 'link.yourbrand.com',
|
||||
condition: { field: 'operation', value: 'create_link' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'originalURL',
|
||||
title: 'Original URL',
|
||||
type: 'long-input',
|
||||
placeholder: 'https://www.example.com/very/long/path/to/page',
|
||||
condition: { field: 'operation', value: 'create_link' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'path',
|
||||
title: 'Custom Path (Optional)',
|
||||
type: 'short-input',
|
||||
placeholder: 'my-custom-path',
|
||||
condition: { field: 'operation', value: 'create_link' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'domainId',
|
||||
title: 'Domain ID',
|
||||
type: 'short-input',
|
||||
placeholder: '12345',
|
||||
condition: { field: 'operation', value: 'list_links' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'limit',
|
||||
title: 'Limit (1–150)',
|
||||
type: 'short-input',
|
||||
placeholder: '50',
|
||||
condition: { field: 'operation', value: 'list_links' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'dateSortOrder',
|
||||
title: 'Sort Order',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Descending', id: 'desc' },
|
||||
{ label: 'Ascending', id: 'asc' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'list_links' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
value: () => 'desc',
|
||||
},
|
||||
{
|
||||
id: 'pageToken',
|
||||
title: 'Page Token',
|
||||
type: 'short-input',
|
||||
placeholder: 'Next page token',
|
||||
condition: { field: 'operation', value: 'list_links' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'linkId',
|
||||
title: 'Short.io Link ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'lnk_abc123_abcdef',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['get_qr_code', 'get_analytics', 'delete_link'],
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
title: 'QR Format',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'PNG', id: 'png' },
|
||||
{ label: 'SVG', id: 'svg' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'get_qr_code' },
|
||||
required: false,
|
||||
value: () => 'png',
|
||||
},
|
||||
{
|
||||
id: 'size',
|
||||
title: 'QR Size (1–99)',
|
||||
type: 'short-input',
|
||||
placeholder: '10',
|
||||
condition: { field: 'operation', value: 'get_qr_code' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'color',
|
||||
title: 'QR Color (hex)',
|
||||
type: 'short-input',
|
||||
placeholder: '000000',
|
||||
condition: { field: 'operation', value: 'get_qr_code' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'backgroundColor',
|
||||
title: 'Background Color (hex)',
|
||||
type: 'short-input',
|
||||
placeholder: 'FFFFFF',
|
||||
condition: { field: 'operation', value: 'get_qr_code' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'period',
|
||||
title: 'Statistics Period',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Today', id: 'today' },
|
||||
{ label: 'Yesterday', id: 'yesterday' },
|
||||
{ label: 'This Week', id: 'week' },
|
||||
{ label: 'Last 7 Days', id: 'last_7_days' },
|
||||
{ label: 'This Month', id: 'month' },
|
||||
{ label: 'Last Month', id: 'lastmonth' },
|
||||
{ label: 'Last 30 Days', id: 'last_30_days' },
|
||||
{ label: 'All Time', id: 'all_time' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'get_analytics' },
|
||||
required: true,
|
||||
value: () => 'last_30_days',
|
||||
},
|
||||
{
|
||||
id: 'tz',
|
||||
title: 'Timezone',
|
||||
type: 'short-input',
|
||||
placeholder: 'UTC',
|
||||
condition: { field: 'operation', value: 'get_analytics' },
|
||||
required: false,
|
||||
mode: 'advanced',
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
'short_io_create_link',
|
||||
'short_io_list_domains',
|
||||
'short_io_list_links',
|
||||
'short_io_delete_link',
|
||||
'short_io_get_qr_code',
|
||||
'short_io_get_analytics',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => `short_io_${params.operation}`,
|
||||
params: (params) => {
|
||||
const { apiKey, operation, size, domainId, limit, dateSortOrder, ...rest } = params
|
||||
const out: Record<string, unknown> = { ...rest, apiKey }
|
||||
if (size !== undefined && size !== '') {
|
||||
const n = Number(size)
|
||||
if (!Number.isNaN(n) && n >= 1 && n <= 99) out.size = n
|
||||
}
|
||||
if (operation === 'list_links' && domainId !== undefined && domainId !== '') {
|
||||
const d = Number(domainId)
|
||||
if (!Number.isNaN(d)) out.domainId = d
|
||||
}
|
||||
if (operation === 'list_links' && limit !== undefined && limit !== '') {
|
||||
const l = Number(limit)
|
||||
if (!Number.isNaN(l) && l >= 1 && l <= 150) out.limit = l
|
||||
}
|
||||
if (operation === 'list_links' && dateSortOrder !== undefined && dateSortOrder !== '') {
|
||||
out.dateSortOrder = dateSortOrder
|
||||
}
|
||||
return out
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
apiKey: { type: 'string', description: 'Secret API Key' },
|
||||
operation: { type: 'string', description: 'Short.io operation to perform' },
|
||||
domain: { type: 'string', description: 'Your registered Short.io custom domain' },
|
||||
originalURL: { type: 'string', description: 'The original long URL to shorten' },
|
||||
path: { type: 'string', description: 'Optional custom path for the short link' },
|
||||
domainId: { type: 'number', description: 'Domain ID (from List Domains)' },
|
||||
limit: { type: 'number', description: 'Max links to return (1–150)' },
|
||||
dateSortOrder: { type: 'string', description: 'Sort order: asc or desc' },
|
||||
pageToken: { type: 'string', description: 'Pagination token for List Links' },
|
||||
linkId: { type: 'string', description: 'The Short.io internal link ID string' },
|
||||
type: { type: 'string', description: 'QR output format: png or svg' },
|
||||
size: { type: 'number', description: 'QR size 1–99' },
|
||||
color: { type: 'string', description: 'QR color hex' },
|
||||
backgroundColor: { type: 'string', description: 'QR background color hex' },
|
||||
period: {
|
||||
type: 'string',
|
||||
description: 'Statistics period (e.g. today, last_30_days, all_time)',
|
||||
},
|
||||
tz: { type: 'string', description: 'Timezone for statistics (e.g. UTC)' },
|
||||
},
|
||||
outputs: {
|
||||
shortURL: { type: 'string', description: 'The generated short link' },
|
||||
idString: { type: 'string', description: 'The Short.io link ID' },
|
||||
originalURL: { type: 'string', description: 'The original long URL' },
|
||||
path: { type: 'string', description: 'The path/slug of the short link' },
|
||||
createdAt: { type: 'string', description: 'ISO 8601 creation timestamp' },
|
||||
domains: { type: 'array', description: 'List of domains (from List Domains)' },
|
||||
count: { type: 'number', description: 'Number of domains or links returned' },
|
||||
links: { type: 'array', description: 'List of links (from List Links)' },
|
||||
nextPageToken: { type: 'string', description: 'Pagination token for next page' },
|
||||
deleted: { type: 'boolean', description: 'Whether the link was deleted' },
|
||||
file: { type: 'file', description: 'Generated QR code image file' },
|
||||
totalClicks: { type: 'number', description: 'Total clicks' },
|
||||
humanClicks: { type: 'number', description: 'Human clicks' },
|
||||
totalClicksChange: { type: 'string', description: 'Change in total clicks vs previous period' },
|
||||
humanClicksChange: { type: 'string', description: 'Change in human clicks vs previous period' },
|
||||
referer: { type: 'array', description: 'Referrer breakdown (referer, score)' },
|
||||
country: { type: 'array', description: 'Country breakdown (countryName, country, score)' },
|
||||
browser: { type: 'array', description: 'Browser breakdown (browser, score)' },
|
||||
os: { type: 'array', description: 'OS breakdown (os, score)' },
|
||||
city: { type: 'array', description: 'City breakdown (city, name, countryCode, score)' },
|
||||
device: { type: 'array', description: 'Device breakdown' },
|
||||
social: { type: 'array', description: 'Social source breakdown (social, score)' },
|
||||
utmMedium: { type: 'array', description: 'UTM medium breakdown' },
|
||||
utmSource: { type: 'array', description: 'UTM source breakdown' },
|
||||
utmCampaign: { type: 'array', description: 'UTM campaign breakdown' },
|
||||
clickStatistics: {
|
||||
type: 'json',
|
||||
description: 'Time-series click data (datasets with x/y per interval)',
|
||||
},
|
||||
interval: {
|
||||
type: 'json',
|
||||
description: 'Date range (startDate, endDate, prevStartDate, prevEndDate, tz)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -141,6 +141,7 @@ import { ServiceNowBlock } from '@/blocks/blocks/servicenow'
|
||||
import { SftpBlock } from '@/blocks/blocks/sftp'
|
||||
import { SharepointBlock } from '@/blocks/blocks/sharepoint'
|
||||
import { ShopifyBlock } from '@/blocks/blocks/shopify'
|
||||
import { ShortIoBlock } from '@/blocks/blocks/short_io'
|
||||
import { SimilarwebBlock } from '@/blocks/blocks/similarweb'
|
||||
import { SlackBlock } from '@/blocks/blocks/slack'
|
||||
import { SmtpBlock } from '@/blocks/blocks/smtp'
|
||||
@@ -345,6 +346,7 @@ export const registry: Record<string, BlockConfig> = {
|
||||
sftp: SftpBlock,
|
||||
sharepoint: SharepointBlock,
|
||||
shopify: ShopifyBlock,
|
||||
short_io: ShortIoBlock,
|
||||
similarweb: SimilarwebBlock,
|
||||
slack: SlackBlock,
|
||||
smtp: SmtpBlock,
|
||||
|
||||
@@ -76,7 +76,6 @@ export function ApiIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function ConditionalIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
@@ -3998,7 +3997,7 @@ export function LoopsIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 256 256' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fill='#FD4E00'
|
||||
fill='currentColor'
|
||||
d='M192.352 88.042c0-7.012-5.685-12.697-12.697-12.697s-12.697 5.685-12.697 12.697c0 .634.052 1.255.142 1.866a25.248 25.248 0 0 0-4.9-.49c-14.006 0-25.36 11.354-25.36 25.36 0 1.63.16 3.222.456 4.765a37.8 37.8 0 0 0-9.296-1.173c-20.95 0-37.935 16.985-37.935 37.935S107.05 194.24 128 194.24s37.935-16.985 37.935-37.935a37.7 37.7 0 0 0-3.78-16.555 25.2 25.2 0 0 0 12.487-3.336 25.2 25.2 0 0 0 4.558 3.336v.02c14.006 0 25.36-11.354 25.36-25.36 0-12.48-9.018-22.855-20.888-24.996a12.6 12.6 0 0 0 8.68-11.972m-77.05 68.263c0-7.012 5.685-12.697 12.697-12.697s12.697 5.685 12.697 12.697c0 7.013-5.685 12.697-12.697 12.697s-12.697-5.685-12.697-12.697'
|
||||
/>
|
||||
</svg>
|
||||
@@ -4542,7 +4541,7 @@ export function DatabricksIcon(props: SVGProps<SVGSVGElement>) {
|
||||
<svg {...props} viewBox='0 0 241 266' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M228.085 109.654L120.615 171.674L5.53493 105.41L0 108.475V156.582L120.615 225.911L228.085 164.128V189.596L120.615 251.615L5.53493 185.351L0 188.417V196.67L120.615 266L241 196.67V148.564L235.465 145.498L120.615 211.527L12.9148 149.743V124.275L120.615 186.059L241 116.729V69.3298L235.004 65.7925L120.615 131.585L18.4498 73.1028L120.615 14.3848L204.562 62.7269L211.942 58.4823V52.5869L120.615 0L0 69.3298V76.8759L120.615 146.206L228.085 84.1862V109.654Z'
|
||||
fill='#FF3621'
|
||||
fill='#F9F7F4'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
@@ -6012,3 +6011,20 @@ export function HexIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function ShortIoIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 64 65' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect width='64' height='65' fill='#FFFFFF' />
|
||||
<path
|
||||
d='M41.1 45.7c0 2-.8 3.5-2.5 4.6-1.6 1-3.8 1.6-6.5 1.6-3.4 0-6-.8-8-2.3-2-1.6-3-3.6-3.2-6.1l-16.3-.4c0 4.1 1.2 7.8 3.6 11.1A24 24 0 0 0 18 62c2.2 1 4.5 1.7 7 2.2l.4.1H0V.2h24.9A25.4 25.4 0 0 0 9.3 9.5C7.1 12.5 6 15.9 6 19.7c0 4.2.9 7.6 2.6 10.1 1.7 2.5 4 4.4 6.8 5.7 2.8 1.3 6.3 2.3 10.6 3.2 4.4.9 7.5 1.6 9.5 2.2 1.9.5 3.3 1.1 4.3 1.9.8.6 1.3 1.6 1.3 2.9Z'
|
||||
fill='#0BB07D'
|
||||
/>
|
||||
<path d='M25.3 64.2h-.6l.1-.1.5.1Z' fill='#33333D' />
|
||||
<path
|
||||
d='M64 64.2H38.1a28 28 0 0 0 7.1-2.2 23 23 0 0 0 9.4-7.6c2.2-3.2 3.4-6.8 3.4-10.8a17 17 0 0 0-2.6-9.8c-1.7-2.4-4-4.3-6.9-5.5a54.4 54.4 0 0 0-10.8-3.1c-4.3-.8-7.3-1.5-9.2-2.1a12 12 0 0 1-4.2-1.8c-.9-.7-1.3-1.7-1.3-3 0-1.9.7-3.3 2.2-4.3 1.5-1 3.4-1.5 5.8-1.5 2.7 0 4.9.7 6.5 2.1a7.8 7.8 0 0 1 2.7 5.4h16.4c0-3.8-1.1-7.3-3.3-10.5a23 23 0 0 0-9.1-7.4c-2.1-1-4.4-1.7-6.8-2.1H64v64.2Z'
|
||||
fill='#383738'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useCallback } from 'react'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import type { WorkflowDeploymentVersionResponse } from '@/lib/workflows/persistence/utils'
|
||||
@@ -210,13 +209,6 @@ export function useChatDeploymentInfo(workflowId: string | null, options?: { ena
|
||||
enabled: Boolean(chatId) && statusQuery.isSuccess && (options?.enabled ?? true),
|
||||
})
|
||||
|
||||
const refetch = useCallback(async () => {
|
||||
const statusResult = await statusQuery.refetch()
|
||||
if (statusResult.data?.deployment?.id) {
|
||||
await detailQuery.refetch()
|
||||
}
|
||||
}, [statusQuery.refetch, detailQuery.refetch])
|
||||
|
||||
return {
|
||||
isLoading:
|
||||
statusQuery.isLoading || Boolean(statusQuery.data?.isDeployed && detailQuery.isLoading),
|
||||
@@ -224,7 +216,12 @@ export function useChatDeploymentInfo(workflowId: string | null, options?: { ena
|
||||
error: statusQuery.error ?? detailQuery.error,
|
||||
chatExists: statusQuery.data?.isDeployed ?? false,
|
||||
existingChat: detailQuery.data ?? null,
|
||||
refetch,
|
||||
refetch: async () => {
|
||||
await statusQuery.refetch()
|
||||
if (statusQuery.data?.deployment?.id) {
|
||||
await detailQuery.refetch()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export const greenhouseGetApplicationTool: ToolConfig<
|
||||
|
||||
request: {
|
||||
url: (params: GreenhouseGetApplicationParams) =>
|
||||
`https://harvest.greenhouse.io/v1/applications/${params.applicationId.trim()}`,
|
||||
`https://harvest.greenhouse.io/v1/applications/${params.applicationId}`,
|
||||
method: 'GET',
|
||||
headers: (params: GreenhouseGetApplicationParams) => ({
|
||||
Authorization: `Basic ${btoa(`${params.apiKey}:`)}`,
|
||||
@@ -31,7 +31,7 @@ export const greenhouseGetCandidateTool: ToolConfig<
|
||||
|
||||
request: {
|
||||
url: (params: GreenhouseGetCandidateParams) =>
|
||||
`https://harvest.greenhouse.io/v1/candidates/${params.candidateId.trim()}`,
|
||||
`https://harvest.greenhouse.io/v1/candidates/${params.candidateId}`,
|
||||
method: 'GET',
|
||||
headers: (params: GreenhouseGetCandidateParams) => ({
|
||||
Authorization: `Basic ${btoa(`${params.apiKey}:`)}`,
|
||||
@@ -25,7 +25,7 @@ export const greenhouseGetJobTool: ToolConfig<GreenhouseGetJobParams, Greenhouse
|
||||
|
||||
request: {
|
||||
url: (params: GreenhouseGetJobParams) =>
|
||||
`https://harvest.greenhouse.io/v1/jobs/${params.jobId.trim()}`,
|
||||
`https://harvest.greenhouse.io/v1/jobs/${params.jobId}`,
|
||||
method: 'GET',
|
||||
headers: (params: GreenhouseGetJobParams) => ({
|
||||
Authorization: `Basic ${btoa(`${params.apiKey}:`)}`,
|
||||
@@ -25,7 +25,7 @@ export const greenhouseGetUserTool: ToolConfig<GreenhouseGetUserParams, Greenhou
|
||||
|
||||
request: {
|
||||
url: (params: GreenhouseGetUserParams) =>
|
||||
`https://harvest.greenhouse.io/v1/users/${params.userId.trim()}`,
|
||||
`https://harvest.greenhouse.io/v1/users/${params.userId}`,
|
||||
method: 'GET',
|
||||
headers: (params: GreenhouseGetUserParams) => ({
|
||||
Authorization: `Basic ${btoa(`${params.apiKey}:`)}`,
|
||||
@@ -1,14 +1,14 @@
|
||||
import { greenhouseGetApplicationTool } from '@/tools/greenhouse/get_application'
|
||||
import { greenhouseGetCandidateTool } from '@/tools/greenhouse/get_candidate'
|
||||
import { greenhouseGetJobTool } from '@/tools/greenhouse/get_job'
|
||||
import { greenhouseGetUserTool } from '@/tools/greenhouse/get_user'
|
||||
import { greenhouseListApplicationsTool } from '@/tools/greenhouse/list_applications'
|
||||
import { greenhouseListCandidatesTool } from '@/tools/greenhouse/list_candidates'
|
||||
import { greenhouseListDepartmentsTool } from '@/tools/greenhouse/list_departments'
|
||||
import { greenhouseListJobStagesTool } from '@/tools/greenhouse/list_job_stages'
|
||||
import { greenhouseListJobsTool } from '@/tools/greenhouse/list_jobs'
|
||||
import { greenhouseListOfficesTool } from '@/tools/greenhouse/list_offices'
|
||||
import { greenhouseListUsersTool } from '@/tools/greenhouse/list_users'
|
||||
import { greenhouseGetApplicationTool } from '@/tools/greenhouse/get-application'
|
||||
import { greenhouseGetCandidateTool } from '@/tools/greenhouse/get-candidate'
|
||||
import { greenhouseGetJobTool } from '@/tools/greenhouse/get-job'
|
||||
import { greenhouseGetUserTool } from '@/tools/greenhouse/get-user'
|
||||
import { greenhouseListApplicationsTool } from '@/tools/greenhouse/list-applications'
|
||||
import { greenhouseListCandidatesTool } from '@/tools/greenhouse/list-candidates'
|
||||
import { greenhouseListDepartmentsTool } from '@/tools/greenhouse/list-departments'
|
||||
import { greenhouseListJobStagesTool } from '@/tools/greenhouse/list-job-stages'
|
||||
import { greenhouseListJobsTool } from '@/tools/greenhouse/list-jobs'
|
||||
import { greenhouseListOfficesTool } from '@/tools/greenhouse/list-offices'
|
||||
import { greenhouseListUsersTool } from '@/tools/greenhouse/list-users'
|
||||
|
||||
export {
|
||||
greenhouseGetApplicationTool,
|
||||
|
||||
@@ -87,7 +87,7 @@ export const greenhouseListCandidatesTool: ToolConfig<
|
||||
if (params.updated_after) url.searchParams.append('updated_after', params.updated_after)
|
||||
if (params.updated_before) url.searchParams.append('updated_before', params.updated_before)
|
||||
if (params.job_id) url.searchParams.append('job_id', params.job_id)
|
||||
if (params.email) url.searchParams.append('email_address', params.email)
|
||||
if (params.email) url.searchParams.append('email', params.email)
|
||||
if (params.candidate_ids) url.searchParams.append('candidate_ids', params.candidate_ids)
|
||||
return url.toString()
|
||||
},
|
||||
@@ -45,7 +45,7 @@ export const greenhouseListJobStagesTool: ToolConfig<
|
||||
|
||||
request: {
|
||||
url: (params: GreenhouseListJobStagesParams) => {
|
||||
const url = new URL(`https://harvest.greenhouse.io/v1/jobs/${params.jobId.trim()}/stages`)
|
||||
const url = new URL(`https://harvest.greenhouse.io/v1/jobs/${params.jobId}/stages`)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
@@ -95,13 +95,13 @@ export const loopsCreateContactTool: ToolConfig<
|
||||
Object.assign(body, props)
|
||||
}
|
||||
|
||||
body.email = params.email.trim()
|
||||
if (params.firstName) body.firstName = params.firstName.trim()
|
||||
if (params.lastName) body.lastName = params.lastName.trim()
|
||||
if (params.source) body.source = params.source.trim()
|
||||
body.email = params.email
|
||||
if (params.firstName) body.firstName = params.firstName
|
||||
if (params.lastName) body.lastName = params.lastName
|
||||
if (params.source) body.source = params.source
|
||||
if (params.subscribed != null) body.subscribed = params.subscribed
|
||||
if (params.userGroup) body.userGroup = params.userGroup.trim()
|
||||
if (params.userId) body.userId = params.userId.trim()
|
||||
if (params.userGroup) body.userGroup = params.userGroup
|
||||
if (params.userId) body.userId = params.userId
|
||||
|
||||
if (params.mailingLists) {
|
||||
body.mailingLists =
|
||||
|
||||
@@ -46,8 +46,8 @@ export const loopsDeleteContactTool: ToolConfig<
|
||||
throw new Error('At least one of email or userId is required to delete a contact')
|
||||
}
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.email) body.email = params.email.trim()
|
||||
if (params.userId) body.userId = params.userId.trim()
|
||||
if (params.email) body.email = params.email
|
||||
if (params.userId) body.userId = params.userId
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
@@ -37,8 +37,8 @@ export const loopsFindContactTool: ToolConfig<LoopsFindContactParams, LoopsFindC
|
||||
throw new Error('At least one of email or userId is required to find a contact')
|
||||
}
|
||||
const base = 'https://app.loops.so/api/v1/contacts/find'
|
||||
if (params.email) return `${base}?email=${encodeURIComponent(params.email.trim())}`
|
||||
return `${base}?userId=${encodeURIComponent(params.userId!.trim())}`
|
||||
if (params.email) return `${base}?email=${encodeURIComponent(params.email)}`
|
||||
return `${base}?userId=${encodeURIComponent(params.userId!)}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
|
||||
@@ -64,8 +64,8 @@ export const loopsSendEventTool: ToolConfig<LoopsSendEventParams, LoopsSendEvent
|
||||
eventName: params.eventName,
|
||||
}
|
||||
|
||||
if (params.email) body.email = params.email.trim()
|
||||
if (params.userId) body.userId = params.userId.trim()
|
||||
if (params.email) body.email = params.email
|
||||
if (params.userId) body.userId = params.userId
|
||||
|
||||
if (params.eventProperties) {
|
||||
body.eventProperties =
|
||||
|
||||
@@ -64,8 +64,8 @@ export const loopsSendTransactionalEmailTool: ToolConfig<
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
email: params.email.trim(),
|
||||
transactionalId: params.transactionalId.trim(),
|
||||
email: params.email,
|
||||
transactionalId: params.transactionalId,
|
||||
}
|
||||
|
||||
if (params.dataVariables) {
|
||||
|
||||
@@ -99,13 +99,13 @@ export const loopsUpdateContactTool: ToolConfig<
|
||||
Object.assign(body, props)
|
||||
}
|
||||
|
||||
if (params.email) body.email = params.email.trim()
|
||||
if (params.userId) body.userId = params.userId.trim()
|
||||
if (params.firstName) body.firstName = params.firstName.trim()
|
||||
if (params.lastName) body.lastName = params.lastName.trim()
|
||||
if (params.source) body.source = params.source.trim()
|
||||
if (params.email) body.email = params.email
|
||||
if (params.userId) body.userId = params.userId
|
||||
if (params.firstName) body.firstName = params.firstName
|
||||
if (params.lastName) body.lastName = params.lastName
|
||||
if (params.source) body.source = params.source
|
||||
if (params.subscribed != null) body.subscribed = params.subscribed
|
||||
if (params.userGroup) body.userGroup = params.userGroup.trim()
|
||||
if (params.userGroup) body.userGroup = params.userGroup
|
||||
|
||||
if (params.mailingLists) {
|
||||
body.mailingLists =
|
||||
|
||||
@@ -1744,6 +1744,14 @@ import {
|
||||
shopifyUpdateOrderTool,
|
||||
shopifyUpdateProductTool,
|
||||
} from '@/tools/shopify'
|
||||
import {
|
||||
shortIoCreateLinkTool,
|
||||
shortIoDeleteLinkTool,
|
||||
shortIoGetAnalyticsTool,
|
||||
shortIoGetQrCodeTool,
|
||||
shortIoListDomainsTool,
|
||||
shortIoListLinksTool,
|
||||
} from '@/tools/short_io'
|
||||
import {
|
||||
similarwebBounceRateTool,
|
||||
similarwebPagesPerVisitTool,
|
||||
@@ -2573,6 +2581,12 @@ export const tools: Record<string, ToolConfig> = {
|
||||
tavily_extract: tavilyExtractTool,
|
||||
tavily_crawl: tavilyCrawlTool,
|
||||
tavily_map: tavilyMapTool,
|
||||
short_io_create_link: shortIoCreateLinkTool,
|
||||
short_io_list_domains: shortIoListDomainsTool,
|
||||
short_io_list_links: shortIoListLinksTool,
|
||||
short_io_delete_link: shortIoDeleteLinkTool,
|
||||
short_io_get_qr_code: shortIoGetQrCodeTool,
|
||||
short_io_get_analytics: shortIoGetAnalyticsTool,
|
||||
supabase_query: supabaseQueryTool,
|
||||
supabase_insert: supabaseInsertTool,
|
||||
supabase_get_row: supabaseGetRowTool,
|
||||
|
||||
82
apps/sim/tools/short_io/create_link.ts
Normal file
82
apps/sim/tools/short_io/create_link.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { ShortIoCreateLinkParams } from '@/tools/short_io/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
export const shortIoCreateLinkTool: ToolConfig<ShortIoCreateLinkParams, ToolResponse> = {
|
||||
id: 'short_io_create_link',
|
||||
name: 'Short.io Create Link',
|
||||
description: 'Create a short link using your Short.io custom domain.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Short.io Secret API Key',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your registered Short.io custom domain',
|
||||
},
|
||||
originalURL: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The long URL to shorten',
|
||||
},
|
||||
path: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional custom path for the short link',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: 'https://api.short.io/links',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const bodyData: Record<string, string> = {
|
||||
domain: params.domain,
|
||||
originalURL: params.originalURL,
|
||||
}
|
||||
if (params.path) {
|
||||
bodyData.path = params.path
|
||||
}
|
||||
return bodyData
|
||||
},
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text().catch(() => response.statusText)
|
||||
return {
|
||||
success: false,
|
||||
output: { shortURL: '', idString: '', originalURL: '', path: null, createdAt: null },
|
||||
error: `Failed to create short link: ${errorText}`,
|
||||
}
|
||||
}
|
||||
|
||||
const data = await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
shortURL: data.shortURL,
|
||||
idString: data.idString,
|
||||
originalURL: data.originalURL,
|
||||
path: data.path ?? null,
|
||||
createdAt: data.createdAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
shortURL: { type: 'string', description: 'The generated short link URL' },
|
||||
idString: { type: 'string', description: 'The unique Short.io link ID string' },
|
||||
originalURL: { type: 'string', description: 'The original long URL' },
|
||||
path: { type: 'string', description: 'The path/slug of the short link', optional: true },
|
||||
createdAt: { type: 'string', description: 'ISO 8601 creation timestamp', optional: true },
|
||||
},
|
||||
}
|
||||
48
apps/sim/tools/short_io/delete_link.ts
Normal file
48
apps/sim/tools/short_io/delete_link.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { ShortIoDeleteLinkParams } from '@/tools/short_io/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
export const shortIoDeleteLinkTool: ToolConfig<ShortIoDeleteLinkParams, ToolResponse> = {
|
||||
id: 'short_io_delete_link',
|
||||
name: 'Short.io Delete Link',
|
||||
description: 'Delete a short link by ID (e.g. lnk_abc123_abcdef). Rate limit 20/s.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Short.io Secret API Key',
|
||||
},
|
||||
linkId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Link ID to delete',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => `https://api.short.io/links/${encodeURIComponent(params.linkId.trim())}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: params.apiKey,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const err = await response.text().catch(() => response.statusText)
|
||||
return { success: false, output: { deleted: false, idString: '' }, error: err }
|
||||
}
|
||||
const data = await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: data.success === true,
|
||||
idString: data.idString ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether the link was deleted' },
|
||||
idString: { type: 'string', description: 'Deleted link ID', optional: true },
|
||||
},
|
||||
}
|
||||
112
apps/sim/tools/short_io/get_analytics.ts
Normal file
112
apps/sim/tools/short_io/get_analytics.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import type { ShortIoGetAnalyticsParams } from '@/tools/short_io/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
const STATS_PERIOD_MAP: Record<string, string> = {
|
||||
today: 'today',
|
||||
yesterday: 'yesterday',
|
||||
last_7_days: 'last7',
|
||||
last_30_days: 'last30',
|
||||
all_time: 'total',
|
||||
week: 'week',
|
||||
month: 'month',
|
||||
lastmonth: 'lastmonth',
|
||||
}
|
||||
|
||||
export const shortIoGetAnalyticsTool: ToolConfig<ShortIoGetAnalyticsParams, ToolResponse> = {
|
||||
id: 'short_io_get_analytics',
|
||||
name: 'Short.io Get Link Statistics',
|
||||
description:
|
||||
'Fetch click statistics for a Short.io link (Statistics API: totalClicks, humanClicks, referer, country, etc.).',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Short.io Secret API Key',
|
||||
},
|
||||
linkId: { type: 'string', required: true, visibility: 'user-or-llm', description: 'Link ID' },
|
||||
period: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Period: today, yesterday, last7, last30, total, week, month, lastmonth',
|
||||
},
|
||||
tz: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Timezone (default UTC)',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = `https://statistics.short.io/statistics/link/${encodeURIComponent(params.linkId.trim())}`
|
||||
const period = STATS_PERIOD_MAP[params.period] ?? params.period ?? 'last30'
|
||||
const q = new URLSearchParams({ period })
|
||||
if (params.tz) q.set('tz', params.tz)
|
||||
return `${base}?${q.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const err = await response.text().catch(() => response.statusText)
|
||||
return { success: false, output: { totalClicks: 0, humanClicks: 0 }, error: err }
|
||||
}
|
||||
const data = await response.json().catch(() => ({}))
|
||||
const totalClicks = data.totalClicks ?? 0
|
||||
const humanClicks = data.humanClicks ?? totalClicks
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalClicks,
|
||||
humanClicks,
|
||||
totalClicksChange: data.totalClicksChange ?? null,
|
||||
humanClicksChange: data.humanClicksChange ?? null,
|
||||
referer: data.referer ?? [],
|
||||
country: data.country ?? [],
|
||||
browser: data.browser ?? [],
|
||||
os: data.os ?? [],
|
||||
city: data.city ?? [],
|
||||
device: data.device ?? [],
|
||||
social: data.social ?? [],
|
||||
utmMedium: data.utm_medium ?? [],
|
||||
utmSource: data.utm_source ?? [],
|
||||
utmCampaign: data.utm_campaign ?? [],
|
||||
clickStatistics: data.clickStatistics ?? null,
|
||||
interval: data.interval ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
totalClicks: { type: 'number', description: 'Total clicks' },
|
||||
humanClicks: { type: 'number', description: 'Human clicks' },
|
||||
totalClicksChange: { type: 'string', description: 'Change vs previous period', optional: true },
|
||||
humanClicksChange: { type: 'string', description: 'Human clicks change', optional: true },
|
||||
referer: { type: 'array', description: 'Referrer breakdown (referer, score)' },
|
||||
country: { type: 'array', description: 'Country breakdown (countryName, country, score)' },
|
||||
browser: { type: 'array', description: 'Browser breakdown (browser, score)' },
|
||||
os: { type: 'array', description: 'OS breakdown (os, score)' },
|
||||
city: { type: 'array', description: 'City breakdown (city, name, countryCode, score)' },
|
||||
device: { type: 'array', description: 'Device breakdown' },
|
||||
social: { type: 'array', description: 'Social source breakdown (social, score)' },
|
||||
utmMedium: { type: 'array', description: 'UTM medium breakdown' },
|
||||
utmSource: { type: 'array', description: 'UTM source breakdown' },
|
||||
utmCampaign: { type: 'array', description: 'UTM campaign breakdown' },
|
||||
clickStatistics: {
|
||||
type: 'object',
|
||||
description: 'Time-series click data (datasets with x/y points per interval)',
|
||||
optional: true,
|
||||
},
|
||||
interval: {
|
||||
type: 'object',
|
||||
description: 'Date range (startDate, endDate, prevStartDate, prevEndDate, tz)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
93
apps/sim/tools/short_io/get_qr_code.ts
Normal file
93
apps/sim/tools/short_io/get_qr_code.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import type { ShortIoGetQrParams } from '@/tools/short_io/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
export const shortIoGetQrCodeTool: ToolConfig<ShortIoGetQrParams, ToolResponse> = {
|
||||
id: 'short_io_get_qr_code',
|
||||
name: 'Short.io Generate QR Code',
|
||||
description: 'Generate a QR code for a Short.io link (POST /links/qr/{linkIdString}).',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Short.io Secret API Key',
|
||||
},
|
||||
linkId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Link ID (e.g. lnk_abc123_abcdef)',
|
||||
},
|
||||
color: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'QR color hex (e.g. 000000)',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Background color hex (e.g. FFFFFF)',
|
||||
},
|
||||
size: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'QR size 1–99',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Output format: png or svg',
|
||||
},
|
||||
useDomainSettings: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Use domain settings (default true)',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: '/api/tools/short_io/qr',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
apiKey: params.apiKey,
|
||||
linkId: params.linkId,
|
||||
useDomainSettings: params.useDomainSettings ?? true,
|
||||
}
|
||||
if (params.color != null && params.color !== '') body.color = params.color
|
||||
if (params.backgroundColor != null && params.backgroundColor !== '')
|
||||
body.backgroundColor = params.backgroundColor
|
||||
if (params.size != null && params.size >= 1 && params.size <= 99) body.size = params.size
|
||||
if (params.type === 'svg' || params.type === 'png') body.type = params.type
|
||||
return body
|
||||
},
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json().catch(() => ({}))
|
||||
if (!response.ok || !data.success) {
|
||||
return {
|
||||
success: false,
|
||||
output: {},
|
||||
error: data.error || response.statusText,
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data.output,
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
file: {
|
||||
type: 'file',
|
||||
description: 'Generated QR code image file',
|
||||
},
|
||||
},
|
||||
}
|
||||
7
apps/sim/tools/short_io/index.ts
Normal file
7
apps/sim/tools/short_io/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export { shortIoCreateLinkTool } from '@/tools/short_io/create_link'
|
||||
export { shortIoDeleteLinkTool } from '@/tools/short_io/delete_link'
|
||||
export { shortIoGetAnalyticsTool } from '@/tools/short_io/get_analytics'
|
||||
export { shortIoGetQrCodeTool } from '@/tools/short_io/get_qr_code'
|
||||
export { shortIoListDomainsTool } from '@/tools/short_io/list_domains'
|
||||
export { shortIoListLinksTool } from '@/tools/short_io/list_links'
|
||||
export * from './types'
|
||||
41
apps/sim/tools/short_io/list_domains.ts
Normal file
41
apps/sim/tools/short_io/list_domains.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { ShortIoListDomainsParams } from '@/tools/short_io/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
export const shortIoListDomainsTool: ToolConfig<ShortIoListDomainsParams, ToolResponse> = {
|
||||
id: 'short_io_list_domains',
|
||||
name: 'Short.io List Domains',
|
||||
description: 'List Short.io domains. Returns domain IDs and details for use in List Links.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Short.io Secret API Key',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: 'https://api.short.io/api/domains',
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const err = await response.text().catch(() => response.statusText)
|
||||
return { success: false, output: { domains: [], count: 0 }, error: err }
|
||||
}
|
||||
const data = await response.json().catch(() => ({}))
|
||||
const list = Array.isArray(data) ? data : (data.domains ?? data.list ?? [])
|
||||
return {
|
||||
success: true,
|
||||
output: { domains: list, count: list.length },
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
domains: { type: 'array', description: 'List of domain objects (id, hostname, etc.)' },
|
||||
count: { type: 'number', description: 'Number of domains' },
|
||||
},
|
||||
}
|
||||
86
apps/sim/tools/short_io/list_links.ts
Normal file
86
apps/sim/tools/short_io/list_links.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import type { ShortIoListLinksParams } from '@/tools/short_io/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
export const shortIoListLinksTool: ToolConfig<ShortIoListLinksParams, ToolResponse> = {
|
||||
id: 'short_io_list_links',
|
||||
name: 'Short.io List Links',
|
||||
description:
|
||||
'List short links for a domain. Requires domain_id (from List Domains or dashboard). Max 150 per request.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Short.io Secret API Key',
|
||||
},
|
||||
domainId: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain ID (from List Domains)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Max links to return (1–150)',
|
||||
},
|
||||
pageToken: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pagination token from previous response',
|
||||
},
|
||||
dateSortOrder: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort by date: asc or desc',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => {
|
||||
const u = new URL('https://api.short.io/api/links')
|
||||
u.searchParams.set('domain_id', String(params.domainId))
|
||||
if (params.limit != null && params.limit >= 1 && params.limit <= 150) {
|
||||
u.searchParams.set('limit', String(params.limit))
|
||||
}
|
||||
if (params.pageToken) u.searchParams.set('pageToken', params.pageToken)
|
||||
if (params.dateSortOrder === 'asc' || params.dateSortOrder === 'desc') {
|
||||
u.searchParams.set('dateSortOrder', params.dateSortOrder)
|
||||
}
|
||||
return u.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const err = await response.text().catch(() => response.statusText)
|
||||
return { success: false, output: { links: [], count: 0 }, error: err }
|
||||
}
|
||||
const data = await response.json().catch(() => ({}))
|
||||
const links = data.links ?? []
|
||||
const count = data.count ?? links.length
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
links,
|
||||
count,
|
||||
nextPageToken: data.nextPageToken ?? undefined,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
links: {
|
||||
type: 'array',
|
||||
description: 'List of link objects (idString, shortURL, originalURL, path, etc.)',
|
||||
},
|
||||
count: { type: 'number', description: 'Number of links returned' },
|
||||
nextPageToken: { type: 'string', description: 'Token for next page', optional: true },
|
||||
},
|
||||
}
|
||||
40
apps/sim/tools/short_io/types.ts
Normal file
40
apps/sim/tools/short_io/types.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
export interface ShortIoCreateLinkParams {
|
||||
apiKey: string
|
||||
domain: string
|
||||
originalURL: string
|
||||
path?: string
|
||||
}
|
||||
|
||||
export interface ShortIoListDomainsParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface ShortIoListLinksParams {
|
||||
apiKey: string
|
||||
domainId: number
|
||||
limit?: number
|
||||
pageToken?: string
|
||||
dateSortOrder?: 'asc' | 'desc'
|
||||
}
|
||||
|
||||
export interface ShortIoDeleteLinkParams {
|
||||
apiKey: string
|
||||
linkId: string
|
||||
}
|
||||
|
||||
export interface ShortIoGetQrParams {
|
||||
apiKey: string
|
||||
linkId: string
|
||||
color?: string
|
||||
backgroundColor?: string
|
||||
size?: number
|
||||
type?: 'png' | 'svg'
|
||||
useDomainSettings?: boolean
|
||||
}
|
||||
|
||||
export interface ShortIoGetAnalyticsParams {
|
||||
apiKey: string
|
||||
linkId: string
|
||||
period: string
|
||||
tz?: string
|
||||
}
|
||||
Reference in New Issue
Block a user