> ## Documentation Index
> Fetch the complete documentation index at: https://x-preview-mintlify-93ac23a1.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration Guide

> This guide covers the key concepts you need to integrate the Post lookup endpoints into your. Reference for the X API v2 standard tier covering lookup.

export const Button = ({href, children}) => {
  return <div className="not-prose">
    <a href={href}>
      <button className="x-btn">
        <span>{children}</span>
        <svg width="3" height="24" viewBox="0 -9 3 24" class="h-6 rotate-0 overflow-visible"><path d="M0 0L3 3L0 6" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg>
      </button>
    </a>
  </div>;
};

This guide covers the key concepts you need to integrate the Post lookup endpoints into your application.

***

## Authentication

All X API v2 endpoints require authentication. Choose the method that fits your use case:

| Method | Best for | Can access private metrics? |
| :- | :- | :- |
| [OAuth 2.0 App-Only](/resources/fundamentals/authentication#oauth-2-0) | Server-to-server, public data | No |
| [OAuth 2.0 Authorization Code with PKCE](/resources/fundamentals/authentication#oauth-2-0-authorization-code-flow-with-pkce-2) | User-facing apps | Yes (for authorized user's Posts) |
| [OAuth 1.0a User Context](/resources/fundamentals/authentication) | Legacy integrations | Yes (for authorized user's Posts) |

### App-Only authentication

For public Post data, use a Bearer Token:

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl "https://api.x.com/2/tweets/1234567890" \
    -H "Authorization: Bearer $BEARER_TOKEN"
  ```

  ```python Python SDK theme={null}
  from xdk import Client

  client = Client(bearer_token="YOUR_BEARER_TOKEN")

  # Get a single Post by ID
  response = client.posts.get("1234567890")
  print(response.data)
  ```

  ```javascript JavaScript SDK theme={null}
  import { Client } from "@xdevplatform/xdk";

  const client = new Client({ bearerToken: "YOUR_BEARER_TOKEN" });

  const response = await client.posts.get("1234567890");
  console.log(response.data);
  ```
</CodeGroup>

### User Context authentication

To access private metrics, authenticate on behalf of the Post author:

<Warning>
  The following fields require User Context authentication:

  * `tweet.fields.non_public_metrics`
  * `tweet.fields.promoted_metrics`
  * `tweet.fields.organic_metrics`
  * `media.fields.non_public_metrics`
  * `media.fields.promoted_metrics`
  * `media.fields.organic_metrics`
</Warning>

***

## Fields and expansions

The X API v2 returns minimal data by default. Use `fields` and `expansions` to request exactly what you need.

### Default response

```json theme={null}
{
  "data": {
    "id": "1234567890",
    "text": "Hello world!",
    "edit_history_tweet_ids": ["1234567890"]
  }
}
```

### Available fields

<Accordion title="tweet.fields">
  | Field | Description |
  | :- | :- |
  | `created_at` | Post creation timestamp |
  | `author_id` | Author's user ID |
  | `public_metrics` | Like, retweet, reply, quote counts |
  | `entities` | Hashtags, mentions, URLs, cashtags |
  | `attachments` | Media keys, poll IDs |
  | `conversation_id` | Thread identifier |
  | `context_annotations` | Topic/entity classifications |
  | `in_reply_to_user_id` | User being replied to |
  | `lang` | Detected language |
  | `possibly_sensitive` | Sensitive content flag |
  | `reply_settings` | Who can reply |
</Accordion>

<Accordion title="user.fields (requires author_id expansion)">
  | Field | Description |
  | :- | :- |
  | `username` | @handle |
  | `name` | Display name |
  | `profile_image_url` | Avatar URL |
  | `verified` | Verification status |
  | `description` | Bio |
  | `public_metrics` | Follower/following counts |
  | `created_at` | Account creation date |
</Accordion>

<Accordion title="media.fields (requires attachments.media_keys expansion)">
  | Field | Description |
  | :- | :- |
  | `url` | Media URL |
  | `preview_image_url` | Thumbnail URL |
  | `type` | photo, video, animated\_gif |
  | `duration_ms` | Video duration |
  | `height`, `width` | Dimensions |
  | `alt_text` | Accessibility text |
</Accordion>

### Example with fields

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl "https://api.x.com/2/tweets/1234567890?\
  tweet.fields=created_at,public_metrics,entities&\
  expansions=author_id,attachments.media_keys&\
  user.fields=username,verified&\
  media.fields=url,type" \
    -H "Authorization: Bearer $BEARER_TOKEN"
  ```

  ```python title="Python SDK" lines wrap icon="python" theme={null}
  from xdk import Client

  client = Client(bearer_token="YOUR_BEARER_TOKEN")

  # Get a Post with additional fields and expansions
  response = client.posts.get(
      "1234567890",
      tweet_fields=["created_at", "public_metrics", "entities"],
      expansions=["author_id", "attachments.media_keys"],
      user_fields=["username", "verified"],
      media_fields=["url", "type"]
  )

  print(response.data)
  print(response.includes)  # Contains expanded user and media objects
  ```

  ```javascript title="JavaScript SDK" lines wrap icon="square-js" theme={null}
  import { Client } from "@xdevplatform/xdk";

  const client = new Client({ bearerToken: "YOUR_BEARER_TOKEN" });

  const response = await client.posts.get("1234567890", {
    tweetFields: ["created_at", "public_metrics", "entities"],
    expansions: ["author_id", "attachments.media_keys"],
    userFields: ["username", "verified"],
    mediaFields: ["url", "type"],
  });

  console.log(response.data);
  console.log(response.includes); // Contains expanded user and media objects
  ```
</CodeGroup>

***

## Post edits

Posts can be edited up to 5 times within 30 minutes of creation.

### How it works

* Each edit creates a new Post ID
* `edit_history_tweet_ids` contains all versions (oldest first)
* The endpoint always returns the most recent version

### Example response

```json theme={null}
{
  "data": {
    "id": "1234567893",
    "text": "Hello world! (edited twice)",
    "edit_history_tweet_ids": [
      "1234567890",
      "1234567891",
      "1234567893"
    ]
  }
}
```

<Tip>
  Posts retrieved after their 30-minute edit window represent the final version. For real-time use cases, be aware that recently-published Posts may still be edited.
</Tip>

***

## Error handling

### Common errors

| Status | Error | Solution |
| :- | :- | :- |
| 400 | Invalid request | Check parameter formatting |
| 401 | Unauthorized | Verify authentication credentials |
| 403 | Forbidden | Check App permissions |
| 404 | Not Found | Post deleted or doesn't exist |
| 429 | Too Many Requests | Wait and retry (see rate limits) |

### Deleted or protected Posts

If a Post is deleted or from a protected account you don't follow:

* Single Post lookup returns `404`
* Multi-Post lookup omits the Post from results with an `errors` array

```json title="Example response" lines wrap icon="https://mintcdn.com/x-preview-mintlify-93ac23a1/U6qfxffxbzJwOhP1/icons/xds/icon-brackets.svg?fit=max&auto=format&n=U6qfxffxbzJwOhP1&q=85&s=a0efb96fcc5fb4c5f7487ed9268ab594" theme={null}
{
  "data": [
    { "id": "1234567890", "text": "Available post" }
  ],
  "errors": [
    {
      "resource_id": "1234567891",
      "resource_type": "tweet",
      "title": "Not Found Error",
      "detail": "Could not find tweet with id: [1234567891]."
    }
  ]
}
```

***

## Best practices

<CardGroup cols={2}>
  <Card title="Batch requests" icon="layer-group">
    Use the multi-Post endpoint to fetch up to 100 Posts at once, reducing API calls.
  </Card>

  <Card title="Request only needed fields" icon="https://mintcdn.com/x-preview-mintlify-93ac23a1/kz2fbxKd_kFzk10_/icons/xds/icon-filter.svg?fit=max&auto=format&n=kz2fbxKd_kFzk10_&q=85&s=47e8be7fefd65299a43d1ea6b602ec17" width="24" height="24" data-path="icons/xds/icon-filter.svg">
    Specify only the fields you need to minimize response size and processing time.
  </Card>

  <Card title="Cache responses" icon="database">
    Cache Post data locally to reduce repeated requests for the same content.
  </Card>

  <Card title="Handle edits" icon="https://mintcdn.com/x-preview-mintlify-93ac23a1/kz2fbxKd_kFzk10_/icons/xds/icon-history.svg?fit=max&auto=format&n=kz2fbxKd_kFzk10_&q=85&s=a948eb091ab041435525786b4643b8e9" width="24" height="24" data-path="icons/xds/icon-history.svg">
    For real-time apps, consider re-fetching Posts after the 30-minute edit window.
  </Card>
</CardGroup>

***

## Next steps

<CardGroup cols={2}>
  <Card title="API Reference" icon="https://mintcdn.com/x-preview-mintlify-93ac23a1/AO3BvOiXS-lYJQ8t/icons/xds/icon-code.svg?fit=max&auto=format&n=AO3BvOiXS-lYJQ8t&q=85&s=1f5bd3f2c9da04a9409be944c25de90f" href="/x-api/posts/post-lookup-by-post-id" width="24" height="24" data-path="icons/xds/icon-code.svg">
    Complete endpoint documentation
  </Card>

  <Card title="Data dictionary" icon="https://mintcdn.com/x-preview-mintlify-93ac23a1/U6qfxffxbzJwOhP1/icons/xds/icon-book.svg?fit=max&auto=format&n=U6qfxffxbzJwOhP1&q=85&s=3898733930afb551f26f75fbcf5da9ea" href="/x-api/fundamentals/data-dictionary" width="24" height="24" data-path="icons/xds/icon-book.svg">
    All available objects and fields
  </Card>

  <Card title="Sample code" icon="github" href="https://github.com/xdevplatform/Twitter-API-v2-sample-code">
    Working code examples
  </Card>

  <Card title="Error handling" icon="https://mintcdn.com/x-preview-mintlify-93ac23a1/V7UflTh3yFCCdvTB/icons/xds/icon-warning.svg?fit=max&auto=format&n=V7UflTh3yFCCdvTB&q=85&s=b6bf42ebda073bb0da15f5249517527c" href="/x-api/fundamentals/response-codes-and-errors" width="24" height="24" data-path="icons/xds/icon-warning.svg">
    Handle errors gracefully
  </Card>
</CardGroup>
