Lindy CI Integration

SkillAI & models

'Configure CI/CD pipelines for testing Lindy AI agent integrations.

Use Lindy CI Integration in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add Lindy CI Integration and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the Lindy CI Integration skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Lindy CI IntegrationStart free

What this skill tells your AI

The instructions your AI receives, as published by jeremylongshore/tons-of-skills-marketplace in skills/.curated/lindy-ci-integration/SKILL.md and read by ahel’s review.

Overview

Lindy agents run on Lindy's managed platform — CI/CD tests your integration code: webhook receivers, callback handlers, and application logic that interacts with Lindy agents. Test webhook signature verification, payload processing, and error handling without hitting live Lindy endpoints.

Prerequisites

  • GitHub repository with Actions enabled
  • Lindy API key and webhook secret stored as GitHub secrets
  • Node.js project with webhook receiver code
  • Completed lindy-install-auth setup

Instructions

Step 1: Store Secrets in GitHub

gh secret set LINDY_API_KEY --body "lnd_live_xxxxxxxxxxxx"
gh secret set LINDY_WEBHOOK_SECRET --body "whsec_xxxxxxxxxxxx"

Step 2: Create GitHub Actions Workflow

# .github/workflows/lindy-integration.yml
name: Lindy Integration Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - name: Run unit tests
        run: npm test
        env:
          LINDY_WEBHOOK_SECRET: ${{ secrets.LINDY_WEBHOOK_SECRET }}

      - name: Validate webhook handler
        run: npm run test:webhook

      - name: Connectivity check (non-blocking)
        continue-on-error: true
        run: |
          curl -s -o /dev/null -w "%{http_code}" \
            -X POST "https://public.lindy.ai/api/v1/webhooks/health" \
            -H "Authorization: Bearer ${{ secrets.LINDY_API_KEY }}"

Step 3: Write Webhook Handler Tests

// __tests__/webhook-handler.test.ts
import { describe, it, expect, vi } from 'vitest';
import request from 'supertest';
import { app } from '../src/server';

describe('Lindy Webhook Handler', () => {
  const VALID_SECRET = process.env.LINDY_WEBHOOK_SECRET || 'test-secret';

  it('rejects requests without auth header', async () => {
    const res = await request(app)
      .post('/lindy/callback')
      .send({ event: 'test' });
    expect(res.status).toBe(401);
  });

  it('rejects requests with wrong auth token', async () => {
    const res = await request(app)
      .post('/lindy/callback')
      .set('Authorization', 'Bearer wrong-token')
      .send({ event: 'test' });
    expect(res.status).toBe(401);
  });

  it('accepts requests with valid auth token', async () => {
    const res = await request(app)
      .post('/lindy/callback')
      .set('Authorization', `Bearer ${VALID_SECRET}`)
      .set('Content-Type', 'application/json')
      .send({
        taskId: 'task_123',
        status: 'completed',
        result: { summary: 'Test result' },
      });
    expect(res.status).toBe(200);
    expect(res.body.received).toBe(true);
  });

  it('handles malformed payload gracefully', async () => {
    const res = await request(app)
      .post('/lindy/callback')
      .set('Authorization', `Bearer ${VALID_SECRET}`)
      .set('Content-Type', 'application/json')
      .send('not-json');
    expect(res.status).toBeLessThan(500);
  });

  it('processes webhook payload fields correctly', async () => {
    const payload = {
      taskId: 'task_456',
      status: 'completed',
      result: {
        classification: 'billing',
        sentiment: 'neutral',
        summary: 'Customer asks about invoice #789',
      },
    };

    const res = await request(app)
      .post('/lindy/callback')
      .set('Authorization', `Bearer ${VALID_SECRET}`)
      .set('Content-Type', 'application/json')
      .send(payload);

    expect(res.status).toBe(200);
  });
});

Step 4: Add Smoke Test for Live Connectivity

// __tests__/connectivity.test.ts
import { describe, it, expect } from 'vitest';

describe('Lindy Connectivity (smoke)', () => {
  it('can reach Lindy webhook endpoint', async () => {
    const webhookUrl = process.env.LINDY_WEBHOOK_URL;
    if (!webhookUrl) {
      console.warn('LINDY_WEBHOOK_URL not set, skipping connectivity test');
      return;
    }

    const response = await fetch(webhookUrl, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.LINDY_WEBHOOK_SECRET}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ test: true, ci: true }),
    });

    expect(response.ok).toBe(true);
  });
});

Step 5: PR Status Check

# Add to existing workflow
      - name: Post test results
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const status = '${{ job.status }}' === 'success' ? 'Passed' : 'Failed';
            if (context.payload.pull_request) {
              github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.payload.pull_request.number,
                body: `Lindy Integration Tests: **${status}**`
              });
            }

Test Categories

CategoryWhat It TestsRequires Live Lindy?
Auth verificationWebhook signature checkingNo
Payload processingData extraction and transformationNo
Error handlingMalformed input, edge casesNo
ConnectivityWebhook endpoint reachabilityYes (non-blocking)
End-to-endFull trigger -> callback cycleYes

Error Handling

IssueCauseSolution
Secret not found in CINot configuredgh secret set LINDY_WEBHOOK_SECRET
Connectivity test failsLindy endpoint unreachable in CIMark as continue-on-error: true
Tests timeoutNetwork latencySet timeout-minutes: 10 on job
Flaky live testsLindy processing delayAdd retry logic or mock external calls

Output

Produce a CI integration record containing the workflow trigger, test fixtures, required secrets by name only, failure ownership, and the command or dashboard evidence proving that the automation ran against a non-production agent.

Examples

For a pull request, trigger a disposable Lindy test agent with fixed fixture input, wait for its terminal status, and fail the workflow when the expected action is absent or the agent reports an error. Keep the production agent ID out of the workflow and promote only after the fixture result is reviewed.

Resources

Next Steps

Proceed to lindy-deploy-integration for deployment automation.

Signals

GitHub stars
3k
Forks
415
Last commit
Oct 2026
Advanced
Item type
skill
Key
lindy-ci-integration
Source
github.com/jeremylongshore/tons-of-skills-marketplace