> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xquik.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pipedream

> Build Xquik Pipedream components with API-key auth, starter actions, monitor-event sources, and extraction polling

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

Use Xquik in Pipedream when a workflow needs X (Twitter) search, account lookups, trends, publishing, extraction jobs, monitors, or webhook automation with one API key.

Start with a source-available component package. Keep the first release small: one app file, eight actions, and two sources. Add more endpoints after workflows repeatedly fall back to a manual API request.

## Prerequisites

* [Xquik API key](/quickstart)
* Pipedream account
* Node.js 18+
* Pipedream CLI installed and authenticated

```bash theme={null}
npm install -g @pipedream/cli
pd login
```

## Component Shape

<CardGroup cols={2}>
  <Card title="App" icon="app-window">
    `components/xquik/app/xquik.app.ts`
  </Card>

  <Card title="Auth" icon="key-round">
    API key prop injected as `x-api-key`.
  </Card>

  <Card title="Base URL" icon="link">
    `https://xquik.com/api/v1`
  </Card>

  <Card title="Actions" icon="play">
    Get Tweet, Search Tweets, Get User, Get Trends, Create Tweet, Create Extraction, Create Monitor, and Create Webhook.
  </Card>

  <Card title="Sources" icon="radio">
    Monitor Event Webhook and Extraction Completed Polling.
  </Card>

  <Card title="Shared helper" icon="workflow">
    JSON requests, structured Xquik errors, and `Retry-After` handling.
  </Card>
</CardGroup>

## App File

Create the shared app component first:

```typescript theme={null}
import { axios } from "@pipedream/platform";

export default {
  type: "app",
  app: "xquik",
  propDefinitions: {
    apiKey: {
      type: "string",
      label: "Xquik API Key",
      secret: true,
    },
  },
  methods: {
    async request($, config, apiKey) {
      return axios($, {
        ...config,
        baseURL: "https://xquik.com/api/v1",
        headers: {
          "content-type": "application/json",
          "x-api-key": apiKey,
          ...(config.headers || {}),
        },
      });
    },
  },
};
```

Add `apiKey: { propDefinition: [xquik, "apiKey"] }` to each action and source
that calls `xquik.request`.

Use `GET /account` as the auth smoke test in your first action because it verifies the API key without mutating data.

## Shared Error Handling

Wrap requests so every action and source reports the same remediation:

```typescript theme={null}
function xquikErrorMessage(status: number, body: unknown, headers: Record<string, string>) {
  if (status === 401) return "Authentication failed. Check the Xquik API key.";
  if (status === 402) return "Subscription or credits required. Update billing in Xquik.";
  if (status === 429) {
    const retryAfter = headers["retry-after"];
    return retryAfter
      ? `Rate limited. Retry after ${retryAfter} seconds.`
      : "Rate limited. Retry after the cooldown period.";
  }
  if (typeof body === "object" && body !== null && "message" in body) {
    return String((body as { message: unknown }).message);
  }
  return "Xquik request failed.";
}
```

Pipedream actions should call the helper once per request and export a short `$summary` so the workflow run is scannable.

## Starter Actions

<CardGroup cols={2}>
  <Card title="Get Tweet" icon="message-square">
    Call `GET /x/tweets/{id}` and return one tweet.
  </Card>

  <Card title="Search Tweets" icon="search">
    Call `GET /x/tweets/search` and return an array of tweets.
  </Card>

  <Card title="Get User" icon="user">
    Call `GET /x/users/{id}` and return one user.
  </Card>

  <Card title="Get Trends" icon="trending-up">
    Call `GET /x/trends` and return a trend list.
  </Card>

  <Card title="Create Tweet" icon="send">
    Call `POST /x/tweets` and return created tweet metadata.
  </Card>

  <Card title="Create Extraction" icon="database">
    Call `POST /extractions` and return the job ID and status.
  </Card>

  <Card title="Create Monitor" icon="radio">
    Call `POST /monitors` and return the monitor ID and status.
  </Card>

  <Card title="Create Webhook" icon="webhook">
    Call `POST /webhooks` and return the webhook ID and signing secret.
  </Card>
</CardGroup>

Example Search Tweets action:

```typescript theme={null}
import xquik from "../../app/xquik.app";

export default {
  key: "xquik-search-tweets",
  name: "Search Tweets",
  description: "Search recent X posts with Xquik.",
  version: "0.0.1",
  type: "action",
  props: {
    xquik,
    apiKey: { propDefinition: [xquik, "apiKey"] },
    q: { type: "string", label: "Query" },
    limit: { type: "integer", label: "Limit", optional: true, default: 25 },
  },
  async run({ $ }) {
    const data = await this.xquik.request(
      $,
      {
        method: "GET",
        url: "/x/tweets/search",
        params: { q: this.q, limit: this.limit },
      },
      this.apiKey,
    );

    $.export("$summary", `Found ${(data.tweets || []).length} tweets.`);
    return data.tweets || [];
  },
};
```

## Result Handoff

Use Pipedream exports and source event metadata to pass stable fields between workflow steps. Keep raw API pages out of Slack messages, CRM rows, warehouse loads, and retry queues.

<CardGroup cols={2}>
  <Card title="Search Tweets action" icon="search">
    Export `tweet_count`, `has_more`, and `next_cursor`; return tweet rows with `tweet_id`, `text`, `author_username`, `created_at`, and optional `url`.
  </Card>

  <Card title="User profile action" icon="users">
    Export `user_id`, `username`, `name`, `followers`, `verified`, and `profile_picture`; return one profile row for `GET /x/users/{id}`.
  </Card>

  <Card title="Trend rows" icon="trending-up">
    Export `trend_count` and `woeid`; return trend rows with `name`, `rank`, `query`, and `description`, then keep the selected region with workflow event metadata.
  </Card>

  <Card title="Tweet or reply write" icon="send">
    Send a unique `Idempotency-Key`. Export `id`, `status`, `billing`, `result`, and `statusUrl`. Poll while `terminal` is false. Retry only when `safeToRetry` is true, using a new key.
  </Card>

  <Card title="Media attachments" icon="image">
    For tweets or replies, pass public URLs in `media` and export `tweet_id` or `write_action_id`. For DMs, upload first, pass one `media_id` in `media_ids`, export `message_id`, and leave `reply_to_message_id` unset.
  </Card>

  <Card title="Monitor and webhook setup" icon="radio">
    Export monitor `id`, `username`, `xUserId`, `eventTypes`, `isActive`, and `nextBillingAt`; export webhook `id`, `url`, `eventTypes`, and one-time `secret`. For Pipedream data stores, map production `deliveryId` to `delivery_id` for receiver retry de-dupe and `streamEventId` to `stream_event_id` when one monitor event should process once across endpoint changes.
  </Card>

  <Card title="Monitor event source" icon="fingerprint">
    Emit `deliveryId` for endpoint-level retry de-dupe, `streamEventId` for event-level de-dupe across endpoint changes, and `occurredAt` as `ts`.
  </Card>

  <Card title="Stored Event Replay" icon="activity">
    Call `GET /api/v1/events` with `after` when a workflow needs replay. Export `event_id`, `type`, `monitor_id`, `monitor_type`, `occurred_at`, `has_more`, and `next_cursor`.
  </Card>

  <Card title="Receiver acceptance" icon="copy-check">
    Return `2xx` after accepting duplicate `deliveryId` or `streamEventId`; keep endpoint signing values, raw request body, raw signature, and full headers out of step exports, logs, data stores, Slack messages, CRM rows, and retry queues.
  </Card>

  <Card title="Extraction polling source" icon="database">
    Emit completed job `id`, `tool_type`, and `status`; fetch detail rows and carry `has_more` plus `next_cursor` into warehouse batches.
  </Card>
</CardGroup>

## Source 1: Monitor Event Webhook

Use this for immediate tweet, reply, quote, and retweet alerts.

Setup flow:

1. Pipedream creates an HTTP endpoint for the source.
2. The source calls `POST /webhooks` with that endpoint and selected event types.
3. The user creates or selects an Xquik monitor.
4. Each webhook payload emits one event with a stable ID.

Payload mapping:

<CardGroup cols={3}>
  <Card title="Event ID" icon="fingerprint">
    Map Pipedream `id` to `streamEventId` for event-level de-dupe, or `deliveryId` for endpoint-level de-dupe.
  </Card>

  <Card title="Event Type" icon="bell">
    Map `eventType` to route `tweet.new`, `tweet.reply`, `tweet.quote`, and `tweet.retweet` events.
  </Card>

  <Card title="Occurred At" icon="calendar-clock">
    Map `occurredAt` as the event timestamp.
  </Card>

  <Card title="Username" icon="at-sign">
    Map `username` for account monitor events.
  </Card>

  <Card title="Tweet ID" icon="hash">
    Map `data.id` as the tweet identifier.
  </Card>

  <Card title="Text" icon="type">
    Map `data.text` as the tweet body.
  </Card>

  <Card title="Author Username" icon="user-round">
    Map `data.author.userName` when present. Use `username` as the monitored-account fallback.
  </Card>
</CardGroup>

Keep the webhook secret returned by Xquik and verify `x-xquik-signature` before emitting events.

## Source 2: Extraction Completed Polling

Use this when teams want batch jobs without webhook setup.

```typescript theme={null}
export default {
  key: "xquik-extraction-completed",
  name: "Extraction Completed",
  description: "Emit completed Xquik extraction jobs.",
  version: "0.0.1",
  type: "source",
  props: {
    xquik,
    apiKey: { propDefinition: [xquik, "apiKey"] },
    timer: { type: "$.interface.timer", default: { intervalSeconds: 900 } },
  },
  async run() {
    const data = await this.xquik.request(
      this,
      {
        method: "GET",
        url: "/extractions",
        params: { status: "completed", limit: 25 },
      },
      this.apiKey,
    );

    for (const job of data.extractions || []) {
      this.$emit(job, {
        id: job.id,
        summary: `Extraction ${job.id} completed`,
        ts: Date.parse(job.completedAt || job.updatedAt || job.createdAt),
      });
    }
  },
};
```

## Recipes

### Search Tweets To Slack

<CardGroup cols={2}>
  <Card title="Schedule Trigger" icon="calendar-clock">
    Run the workflow on the reporting cadence.
  </Card>

  <Card title="Xquik Search Tweets" icon="search">
    Call the Search Tweets action and return recent matching posts.
  </Card>

  <Card title="Engagement Filter" icon="funnel">
    Keep only tweets that meet the minimum engagement threshold.
  </Card>

  <Card title="Slack Send Message" icon="message-square">
    Send the selected tweet text, author, and link to the channel.
  </Card>
</CardGroup>

### Monitor Events To CRM

<CardGroup cols={2}>
  <Card title="Monitor Event Source" icon="radio">
    Receive Xquik monitor events from the webhook source.
  </Card>

  <Card title="Event Type Filter" icon="funnel">
    Route `tweet.new`, `tweet.reply`, `tweet.quote`, and `tweet.retweet` events separately.
  </Card>

  <Card title="Get User Enrichment" icon="user">
    Enrich the event with the Get User action before CRM routing.
  </Card>

  <Card title="CRM Upsert" icon="database">
    Upsert by user ID to avoid duplicate account records.
  </Card>
</CardGroup>

### Extraction To Warehouse

<CardGroup cols={2}>
  <Card title="Create Extraction" icon="database">
    Start the extraction job with `POST /extractions`.
  </Card>

  <Card title="Extraction Completed Source" icon="radio">
    Poll for completed jobs before loading rows downstream.
  </Card>

  <Card title="Fetch Extraction Detail" icon="file-text">
    Fetch the completed extraction detail and result rows.
  </Card>

  <Card title="Warehouse Destination" icon="database">
    Send normalized rows to the warehouse destination.
  </Card>
</CardGroup>

## Test Coverage

Add focused tests before sharing the component package:

<CardGroup cols={2}>
  <Card title="Auth Injection" icon="shield-check">
    Every request includes `x-api-key` and never logs the key.
  </Card>

  <Card title="Invalid Key" icon="key-round">
    `401` produces "Authentication failed. Check the Xquik API key."
  </Card>

  <Card title="Rate Limit" icon="timer">
    `429` includes `Retry-After` when present.
  </Card>

  <Card title="Search Action" icon="search">
    Returns an array with stable tweet IDs.
  </Card>

  <Card title="Create Webhook" icon="webhook">
    Sends callback URL and selected event types.
  </Card>

  <Card title="Webhook Source" icon="radio">
    Emits one event per payload with a stable ID.
  </Card>

  <Card title="Polling Source" icon="database">
    Emits only completed extraction jobs.
  </Card>
</CardGroup>

Run component tests and publish privately first:

```bash theme={null}
npm test
pd publish components/xquik/actions/search-tweets/search-tweets.ts
```

## Next Steps

* Read [API Reference](/api-reference/overview) for auth, rate limits, and errors.
* Read [Webhooks](/webhooks/overview) for payload shape and retries.
* Read [Extraction Workflow](/guides/extraction-workflow) for job creation and result pagination.
* Use [Make](/guides/make) or [Zapier](/guides/zapier) when the team wants no-code scenario builders.
