Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
|
||||
|
||||
import { PieceAuth } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { uscreenPublisherApiUrl } from './client';
|
||||
|
||||
export const uscreenAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description: `
|
||||
To get your API key:
|
||||
1. Log in to your Uscreen account
|
||||
2. Contact your Customer Success Manager to have an API key (X-Store-Token) issued.
|
||||
`,
|
||||
required: true,
|
||||
validate: async ({ auth }) => {
|
||||
try {
|
||||
await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `${uscreenPublisherApiUrl}/offers`,
|
||||
headers: {
|
||||
'X-Store-Token': auth,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid API key or insufficient permissions.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,125 @@
|
||||
|
||||
|
||||
import { httpClient, HttpMethod, HttpRequest, QueryParams } from "@activepieces/pieces-common";
|
||||
|
||||
export const uscreenApiUrl = 'https://api.uscreen.io/v1';
|
||||
|
||||
export const uscreenPublisherApiUrl = 'https://uscreen.io/publisher_api/v1';
|
||||
|
||||
|
||||
export interface UscreenProduct {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface UscreenInvoice {
|
||||
id: string;
|
||||
title: string;
|
||||
total: string;
|
||||
amount: string;
|
||||
discount: string;
|
||||
offer_id: string;
|
||||
customer_name: string;
|
||||
customer_email: string;
|
||||
status: string;
|
||||
paid_at: string;
|
||||
created_at: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export class UscreenClient {
|
||||
constructor(private apiKey: string) {}
|
||||
|
||||
/**
|
||||
* Makes an authenticated request to the Uscreen PUBLISHER API.
|
||||
*/
|
||||
async makeRequest<T>(method: HttpMethod, url: string, body?: object, query?: QueryParams): Promise<T> {
|
||||
const request: HttpRequest<object> = {
|
||||
method,
|
||||
url: `${uscreenPublisherApiUrl}${url}`,
|
||||
body: body,
|
||||
queryParams: query,
|
||||
headers: {
|
||||
"X-Store-Token": this.apiKey,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
const { body: responseBody } = await httpClient.sendRequest<T>(request);
|
||||
return responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a paginated list of invoices, sorted by payment date.
|
||||
*/
|
||||
async getInvoices(params: {
|
||||
sort_by: string,
|
||||
status: string,
|
||||
per_page?: number
|
||||
}): Promise<{ items: UscreenInvoice[] }> {
|
||||
|
||||
const query: QueryParams = {
|
||||
sort_by: params.sort_by,
|
||||
status: params.status,
|
||||
};
|
||||
|
||||
if (params.per_page !== undefined) {
|
||||
query['per_page'] = params.per_page.toString();
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.makeRequest<{ items: UscreenInvoice[] }>(
|
||||
HttpMethod.GET,
|
||||
'/invoices',
|
||||
undefined,
|
||||
query
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch Uscreen invoices", e);
|
||||
return { items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches a list of offers (subscriptions).
|
||||
*/
|
||||
async getOffers(): Promise<UscreenProduct[]> {
|
||||
try {
|
||||
return await this.makeRequest<UscreenProduct[]>(
|
||||
HttpMethod.GET,
|
||||
'/offers'
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch Uscreen offers", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of programs (bundles).
|
||||
*/
|
||||
async getPrograms(): Promise<UscreenProduct[]> {
|
||||
try {
|
||||
return await this.makeRequest<UscreenProduct[]>(
|
||||
HttpMethod.GET,
|
||||
'/programs'
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch Uscreen programs", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getCustomers() {
|
||||
try {
|
||||
return await this.makeRequest<{ id: number; email: string }[]>(
|
||||
HttpMethod.GET,
|
||||
'/customers'
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch Uscreen customers", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { UscreenClient, UscreenProduct } from './client';
|
||||
import { uscreenAuth } from './auth';
|
||||
|
||||
export const uscreenProps = {
|
||||
customerId: (required = true) =>
|
||||
Property.Dropdown({
|
||||
auth: uscreenAuth,
|
||||
displayName: 'Customer ID or Email',
|
||||
description: 'The unique ID or email address of the customer.',
|
||||
required: required,
|
||||
refreshers: ['productType'],
|
||||
options: async (context) => {
|
||||
const auth = context['auth'];
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const client = new UscreenClient(auth.secret_text);
|
||||
const customers = await client.getCustomers();
|
||||
return {
|
||||
disabled: false,
|
||||
options: customers.map((customer) => ({
|
||||
label: customer.email,
|
||||
value: customer.id,
|
||||
})),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
productType: (required = true) =>
|
||||
Property.StaticDropdown({
|
||||
displayName: 'Product Type',
|
||||
description: 'The type of product to assign.',
|
||||
required: required,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Program (Bundle)', value: 'program' },
|
||||
{ label: 'Offer (Subscription)', value: 'offer' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
|
||||
productId: (required = true) =>
|
||||
Property.Dropdown({
|
||||
auth: uscreenAuth,
|
||||
displayName: 'Product',
|
||||
description: 'The bundle (program) or subscription (offer) to assign.',
|
||||
required: required,
|
||||
refreshers: ['productType'],
|
||||
options: async (context) => {
|
||||
const auth = context['auth'];
|
||||
|
||||
const propsValue = context['propsValue'] as Record<string, unknown>;
|
||||
const productType = propsValue['productType'] as
|
||||
| 'program'
|
||||
| 'offer'
|
||||
| undefined;
|
||||
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
if (!productType) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Select a Product Type first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
const client = new UscreenClient(auth.secret_text);
|
||||
|
||||
let products: UscreenProduct[] = [];
|
||||
|
||||
if (productType === 'program') {
|
||||
products = await client.getPrograms();
|
||||
} else if (productType === 'offer') {
|
||||
products = await client.getOffers();
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: products.map((product) => ({
|
||||
label: product.name,
|
||||
value: product.id,
|
||||
})),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
webhookInstructions: (required = true) =>
|
||||
Property.MarkDown({
|
||||
value: `## Setup Instructions
|
||||
|
||||
### 1. Access Uscreen Webhook Settings
|
||||
- Log into your **Uscreen Admin Panel**
|
||||
- Navigate to **Settings** > **Webhooks**
|
||||
|
||||
### 2. Create New Webhook
|
||||
- Click **"New Webhook"**
|
||||
- **Callback URL**:
|
||||
\`\`\`text
|
||||
{{webhookUrl}}
|
||||
\`\`\`
|
||||
- Select the appropriate event
|
||||
- Click **Save**`,
|
||||
}),
|
||||
};
|
||||
Reference in New Issue
Block a user