> ## 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.

# Terraform Provider

> Build the Xquik Terraform provider locally and manage X monitors, signed webhooks, tweet actions, API keys, and automation state as infrastructure.

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

Use the Terraform provider when Xquik resources need to live beside the rest of your infrastructure code. It is useful when platform teams want repeatable account monitors, HMAC webhooks, API keys, drafts, tweet actions, profile updates, and support workflows in the same review and state process as the rest of their deployment.

<Note>
  Terraform Registry publication is pending. Until the provider appears in the registry, build it locally and use a Terraform CLI development override.
</Note>

## Install

Clone and build the provider:

```bash theme={null}
git clone https://github.com/Xquik-dev/terraform-provider-x-twitter-scraper.git
cd terraform-provider-x-twitter-scraper
./scripts/build
```

Move the provider binary into a local plugin directory for your platform:

```bash theme={null}
mkdir -p ~/.terraform.d/plugins/xquik-dev/x-twitter-scraper/0.2.0/darwin_arm64
mv terraform-provider-x-twitter-scraper ~/.terraform.d/plugins/xquik-dev/x-twitter-scraper/0.2.0/darwin_arm64/
```

Use the matching platform directory for your machine, such as `linux_amd64`, `linux_arm64`, `darwin_amd64`, `darwin_arm64`, or `windows_amd64`.

## Configure Terraform

Add a development override to `~/.terraformrc`:

```hcl theme={null}
provider_installation {
  dev_overrides {
    "Xquik-dev/x-twitter-scraper" = "/Users/you/.terraform.d/plugins/xquik-dev/x-twitter-scraper/0.2.0/darwin_arm64"
  }

  direct {}
}
```

Then declare the provider in your Terraform project:

```hcl theme={null}
terraform {
  required_providers {
    x-twitter-scraper = {
      source = "Xquik-dev/x-twitter-scraper"
    }
  }
}

provider "x-twitter-scraper" {
  api_key = var.xquik_api_key
}
```

## Authenticate

Use variables or environment variables for credentials:

```bash theme={null}
export X_TWITTER_SCRAPER_API_KEY="xq_YOUR_KEY_HERE"
export X_TWITTER_SCRAPER_BEARER_TOKEN="YOUR_OAUTH_TOKEN"
```

Prefer environment variables for credentials. If you pass credentials through Terraform variables, mark them `sensitive = true` and use an encrypted remote state backend.

## Workflow: Monitor Tweets to Signed Webhooks

Use this workflow when Terraform should own a production tweet monitor and the webhook endpoint that receives signed events for queues, incident tools, social listening dashboards, or CRM enrichment.

The provider resources map to the REST API: `x-twitter-scraper_monitor` creates an account monitor through `POST /monitors`, and `x-twitter-scraper_webhook` creates a signed webhook through `POST /webhooks`. Both resources use Terraform snake\_case arguments that map to the API request fields.

```hcl theme={null}
variable "webhook_url" {
  type = string
}

variable "xquik_api_key" {
  type      = string
  sensitive = true
}

provider "x-twitter-scraper" {
  api_key = var.xquik_api_key
}

resource "x-twitter-scraper_webhook" "alerts" {
  url         = var.webhook_url
  event_types = ["tweet.new", "tweet.reply"]
  is_active   = true
}

resource "x-twitter-scraper_monitor" "xquik_account" {
  username    = "username"
  event_types = ["tweet.new", "tweet.reply"]
  is_active   = true
}

output "monitor_id" {
  value = x-twitter-scraper_monitor.xquik_account.id
}

output "webhook_id" {
  value = x-twitter-scraper_webhook.alerts.id
}

output "webhook_secret" {
  value     = x-twitter-scraper_webhook.alerts.secret
  sensitive = true
}
```

### Request Mapping

<CardGroup cols={2}>
  <Card title="Monitor resource" icon="radio">
    Terraform resource `x-twitter-scraper_monitor` maps to `POST /monitors`. It requires `username` and `event_types`, accepts optional `is_active`, and returns `id`, `x_user_id`, `is_active`, and `created_at` in state.
  </Card>

  <Card title="Webhook resource" icon="webhook">
    Terraform resource `x-twitter-scraper_webhook` maps to `POST /webhooks`. It requires `url` and `event_types`, accepts optional `is_active`, and returns `id`, `secret`, and `created_at` in state.
  </Card>

  <Card title="Event data source" icon="activity">
    Terraform data source `x-twitter-scraper_event` reads one stored monitor event. It requires `id` and returns `type`, `username`, `monitor_id`, `occurred_at`, `x_event_id`, and `data`.
  </Card>
</CardGroup>

Valid monitor and webhook event types are `tweet.new`, `tweet.reply`, `tweet.quote`, and `tweet.retweet`. Webhook URLs must be HTTPS and must be reachable from the public internet.

### Returned Data & Handoff

After `terraform apply`, hand `monitor_id` to operators who need to pause, update, or delete the monitor through Terraform. Hand `webhook_id` to delivery dashboards and support playbooks. Store `webhook_secret` in a secret manager and use it to verify `X-Xquik-Signature`, `X-Xquik-Timestamp`, and `X-Xquik-Nonce` on every delivery.

Production webhook payloads include `deliveryId` and `streamEventId`. Store `deliveryId` for receiver idempotency. Store `streamEventId` when one monitor event must be processed once across retries or endpoint changes. Use `GET /webhooks/{id}/deliveries` to inspect retry state by webhook after apply. Synthetic `webhook.test` requests verify signing only and do not include those production idempotency fields.

Webhook operations are free. Active monitors check every second and cost 21
credits per monitor-hour. Creating one requires the username lookup cost and
the first monitor hour. Monitors may pause when credits run out.

### State & Secrets

Terraform state can contain the webhook `secret` returned at creation time. Use an encrypted backend, restrict state access, and mark every output that references the secret as `sensitive = true`. If the secret is lost or exposed, delete and recreate the webhook so Terraform receives a new signing secret.

## Workflow: Declare Media Tweets and Replies

Use `x-twitter-scraper_x_tweet` when an infrastructure change must create one durable tweet or reply as part of a reviewed apply. The resource maps to `POST /x/tweets`, accepts public media URLs in `media`, and stores the confirmed `tweet_id` in Terraform state.

```hcl theme={null}
resource "x-twitter-scraper_x_tweet" "launch_reply" {
  account           = "myxhandle"
  text              = "Launch assets are ready"
  reply_to_tweet_id = "1893456789012345678"
  media             = ["https://example.com/product-demo.mp4"]
}

output "launch_reply_tweet_id" {
  value = x-twitter-scraper_x_tweet.launch_reply.tweet_id
}
```

### Tweet Resource Mapping

<CardGroup cols={2}>
  <Card title="Tweet resource" icon="send">
    Terraform resource `x-twitter-scraper_x_tweet` maps to `POST /x/tweets`. It requires `account`, accepts optional `text`, `reply_to_tweet_id`, `is_note_tweet`, `community_id`, and `media`, and returns `tweet_id` plus read-only tweet details in state.
  </Card>

  <Card title="Media boundary" icon="image">
    The `media` argument is for public image URLs or exactly one public MP4 URL. Text-only tweets and replies cost 30 credits, and attached media adds 2 credits per started MB. Do not pass uploaded media IDs to this resource; uploaded media IDs are for direct messages through `POST /x/dm/{userId}`.
  </Card>
</CardGroup>

<Warning>
  Generated provider docs may list `media_ids` on `x-twitter-scraper_x_tweet`, but `POST /x/tweets` rejects `media_ids`. Use `media` with public image or MP4 URLs for tweets. Reserve uploaded media IDs for one-item DM `media_ids` through REST, MCP tools, or a generated SDK.
</Warning>

### Tweet Handoff

After `terraform apply`, hand `tweet_id`, `reply_to_tweet_id`, `account`, and the original `media` URLs to the queue, release record, CRM note, or incident timeline that needs to reconcile the post. Keep the media URLs in your own system so a later state refresh does not become the only audit trail.

Terraform state for `x-twitter-scraper_x_tweet` does not expose durable write action fields, media upload resources, or direct-message send resources. Use the REST API, MCP tools, or a generated SDK when a worker must store lifecycle handoffs, upload local media for one-item DM `media_ids`, or store returned DM `message_id`.

## Error Handling

Provider errors surface through Terraform plan and apply output. REST API response semantics match the [error handling guide](/guides/error-handling).

## State & Pagination

Terraform tracks resource state in your configured backend. Data sources and resources use the generated provider schema; review the generated docs in the [provider repository](https://github.com/Xquik-dev/terraform-provider-x-twitter-scraper/tree/main/docs) before adding resources to production state.

Terraform should not be the handoff surface for extraction files. For reply, follower, or tweet search exports, use the REST extraction endpoints, CLI, MCP tools, or generated SDKs to write CSV, JSON, XLSX, or JSON Lines files. Keep Terraform state focused on long-lived resources and IDs that must be reviewed through plan and apply.

## Webhooks & References

* [REST API Overview](/api-reference/overview)
* [API Authentication](/api-reference/authentication)
* [Webhook Overview](/webhooks/overview)
* [Verify HMAC Signatures](/webhooks/verification)
* [Provider Source](https://github.com/Xquik-dev/terraform-provider-x-twitter-scraper)
