Skip to main content
POST
/
rpc
/
Trails
/
GetIntentTransactionHistory
{
  "intents": [
    {
      "id": 123,
      "intentId": "<string>",
      "status": "QUOTED",
      "ownerAddress": "<string>",
      "originChainId": 123,
      "destinationChainId": 123,
      "originIntentAddress": "<string>",
      "destinationIntentAddress": "<string>",
      "depositTransactionHash": "<string>",
      "depositTransactionStatus": "UNKNOWN",
      "originTransactionHash": "<string>",
      "originTransactionStatus": "UNKNOWN",
      "destinationTransactionHash": "<string>",
      "destinationTransactionStatus": "UNKNOWN",
      "originTokenAddress": "<string>",
      "originTokenAmount": 123,
      "originTokenMetadata": {
        "chainId": 123,
        "tokenAddress": "<string>",
        "name": "<string>",
        "symbol": "<string>",
        "decimals": 123,
        "logoUri": "<string>"
      },
      "destinationTokenAddress": "<string>",
      "destinationTokenAmount": 123,
      "destinationTokenMetadata": {
        "chainId": 123,
        "tokenAddress": "<string>",
        "name": "<string>",
        "symbol": "<string>",
        "decimals": 123,
        "logoUri": "<string>"
      },
      "updatedAt": "<string>",
      "createdAt": "<string>"
    }
  ],
  "nextPage": {
    "column": "<string>",
    "before": {},
    "after": {},
    "sort": [
      {
        "column": "<string>",
        "order": "DESC"
      }
    ],
    "pageSize": 123,
    "more": true
  }
}

Overview

The GetIntentTransactionHistory endpoint provides a paginated view of intent transaction history with summary information optimized for display. Unlike SearchIntents, this endpoint returns lightweight IntentSummary objects and supports cursor-based pagination for efficient browsing of large histories.

Use Cases

  • Build transaction history pages with pagination
  • Display user transaction history in UI
  • Create activity feeds
  • Export transaction data
  • Analytics and reporting
  • Mobile apps with infinite scroll

Request Parameters

All parameters are optional:
  • page (Page): Pagination configuration
    • column (string): Column to paginate by (typically “id” or “createdAt”)
    • before (object): Cursor for previous page
    • after (object): Cursor for next page
    • sort (SortBy[]): Sorting configuration
      • column (string): Column to sort by
      • order (SortOrder): DESC or ASC
    • pageSize (number): Number of results per page (default: 20)
    • more (boolean): Indicates if more pages are available

Response

The response includes:
  • intents (IntentSummary[]): Array of intent summary objects
  • nextPage (Page): Pagination cursor for the next page

IntentSummary Structure

Lightweight summary object containing:
  • id (number): Internal database ID
  • intentId (string): Unique intent identifier
  • status (IntentStatus): Current status
  • ownerAddress (string): Wallet address
  • originChainId (number): Source chain ID
  • destinationChainId (number): Destination chain ID
  • originIntentAddress (string): Origin intent contract address
  • destinationIntentAddress (string): Destination intent contract address

Transaction Hashes

  • depositTransactionHash (string): Deposit transaction hash
  • depositTransactionStatus (TransactionStatus): Deposit status
  • originTransactionHash (string): Origin transaction hash
  • originTransactionStatus (TransactionStatus): Origin status
  • destinationTransactionHash (string): Destination transaction hash
  • destinationTransactionStatus (TransactionStatus): Destination status

Token Information

  • originTokenAddress (string): Source token contract
  • originTokenAmount (number): Source token amount
  • originTokenMetadata (TokenMetadata): Source token details (symbol, decimals, logo)
  • destinationTokenAddress (string): Destination token contract
  • destinationTokenAmount (number): Destination token amount
  • destinationTokenMetadata (TokenMetadata): Destination token details

Timestamps

  • createdAt (string): Creation timestamp
  • updatedAt (string): Last update timestamp

Examples

Basic Request (First Page)

const historyResponse = await fetch(
  'https://trails-api.sequence.app/rpc/Trails/GetIntentTransactionHistory',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Access-Key': 'YOUR_ACCESS_KEY'
    },
    body: JSON.stringify({
      page: {
        pageSize: 20,
        sort: [{
          column: 'createdAt',
          order: 'DESC'
        }]
      }
    })
  }
);

const { intents, nextPage } = await historyResponse.json();

console.log(`Loaded ${intents.length} intents`);
intents.forEach(intent => {
  console.log(`${intent.intentId}: ${intent.status}`);
  console.log(`  ${intent.originTokenMetadata.symbol}${intent.destinationTokenMetadata.symbol}`);
  console.log(`  Amount: ${intent.originTokenAmount}${intent.destinationTokenAmount}`);
});

// Check if there are more pages
if (nextPage) {
  console.log('More pages available');
}

Paginated Loading

async function loadAllHistory() {
  let allIntents: IntentSummary[] = [];
  let page: Page | undefined = {
    pageSize: 50,
    sort: [{ column: 'createdAt', order: 'DESC' }]
  };
  
  while (page) {
    const { intents, nextPage } = await fetch(
      'https://trails-api.sequence.app/rpc/Trails/GetIntentTransactionHistory',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Access-Key': 'YOUR_ACCESS_KEY'
        },
        body: JSON.stringify({ page })
      }
    ).then(r => r.json());
    
    allIntents.push(...intents);
    page = nextPage;
    
    console.log(`Loaded ${allIntents.length} intents so far...`);
  }
  
  return allIntents;
}

const allHistory = await loadAllHistory();
console.log(`Total intents: ${allHistory.length}`);

Infinite Scroll Component

import { useState, useEffect, useRef } from 'react';

function IntentTransactionHistory() {
  const [intents, setIntents] = useState<IntentSummary[]>([]);
  const [nextPage, setNextPage] = useState<Page | null>({
    pageSize: 20,
    sort: [{ column: 'createdAt', order: 'DESC' }]
  });
  const [loading, setLoading] = useState(false);
  const observerTarget = useRef(null);
  
  const loadMore = async () => {
    if (!nextPage || loading) return;
    
    setLoading(true);
    try {
      const response = await fetch(
        'https://trails-api.sequence.app/rpc/Trails/GetIntentTransactionHistory',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'X-Access-Key': 'YOUR_ACCESS_KEY'
          },
          body: JSON.stringify({ page: nextPage })
        }
      );
      
      const data = await response.json();
      setIntents(prev => [...prev, ...data.intents]);
      setNextPage(data.nextPage);
    } catch (error) {
      console.error('Failed to load intents:', error);
    } finally {
      setLoading(false);
    }
  };
  
  useEffect(() => {
    const observer = new IntersectionObserver(
      entries => {
        if (entries[0].isIntersecting) {
          loadMore();
        }
      },
      { threshold: 1 }
    );
    
    if (observerTarget.current) {
      observer.observe(observerTarget.current);
    }
    
    return () => observer.disconnect();
  }, [nextPage, loading]);
  
  useEffect(() => {
    loadMore();
  }, []);
  
  return (
    <div className="transaction-history">
      <h2>Transaction History</h2>
      
      <div className="intents-list">
        {intents.map(intent => (
          <IntentCard key={intent.intentId} intent={intent} />
        ))}
      </div>
      
      {loading && <div>Loading...</div>}
      {nextPage && <div ref={observerTarget} />}
      {!nextPage && <div>No more transactions</div>}
    </div>
  );
}

function IntentCard({ intent }: { intent: IntentSummary }) {
  return (
    <div className="intent-card">
      <div className="intent-header">
        <span className="intent-id">{intent.intentId.slice(0, 8)}...</span>
        <span className={`status-${intent.status.toLowerCase()}`}>
          {intent.status}
        </span>
      </div>
      
      <div className="intent-route">
        <div className="token-info">
          <img src={intent.originTokenMetadata.logoUri} alt="" />
          <span>{intent.originTokenMetadata.symbol}</span>
          <span>{intent.originTokenAmount}</span>
        </div>
        <span className="arrow"></span>
        <div className="token-info">
          <img src={intent.destinationTokenMetadata.logoUri} alt="" />
          <span>{intent.destinationTokenMetadata.symbol}</span>
          <span>{intent.destinationTokenAmount}</span>
        </div>
      </div>
      
      <div className="intent-details">
        <div>Chain {intent.originChainId} → Chain {intent.destinationChainId}</div>
        <div>{new Date(intent.createdAt).toLocaleString()}</div>
      </div>
      
      {intent.depositTransactionHash && (
        <div className="transaction-links">
          <a href={getExplorerUrl(intent.originChainId, intent.depositTransactionHash)} 
             target="_blank" rel="noopener noreferrer">
            View Deposit TX
          </a>
          {intent.destinationTransactionHash && (
            <a href={getExplorerUrl(intent.destinationChainId, intent.destinationTransactionHash)} 
               target="_blank" rel="noopener noreferrer">
              View Destination TX
            </a>
          )}
        </div>
      )}
    </div>
  );
}

Sorting Options

// Sort by creation date (newest first)
{
  page: {
    pageSize: 20,
    sort: [{ column: 'createdAt', order: 'DESC' }]
  }
}

// Sort by creation date (oldest first)
{
  page: {
    pageSize: 20,
    sort: [{ column: 'createdAt', order: 'ASC' }]
  }
}

// Sort by ID
{
  page: {
    pageSize: 20,
    sort: [{ column: 'id', order: 'DESC' }]
  }
}

// Multiple sort columns
{
  page: {
    pageSize: 20,
    sort: [
      { column: 'status', order: 'ASC' },
      { column: 'createdAt', order: 'DESC' }
    ]
  }
}

Filtering by Status

async function getCompletedIntents() {
  const { intents } = await fetch(
    'https://trails-api.sequence.app/rpc/Trails/GetIntentTransactionHistory',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Access-Key': 'YOUR_ACCESS_KEY'
      },
      body: JSON.stringify({
        page: {
          pageSize: 100,
          sort: [{ column: 'createdAt', order: 'DESC' }]
        }
      })
    }
  ).then(r => r.json());
  
  return intents.filter(i => i.status === 'SUCCEEDED');
}

Performance Considerations

IntentSummary objects are much lighter than full Intent objects. Use this endpoint for list views and only fetch full intent details when needed using GetIntent.

Best Practices

  1. Use reasonable page sizes: 20-50 items is optimal for most UIs
  2. Implement infinite scroll: Better UX than traditional pagination buttons
  3. Cache responses: Store pages locally to avoid refetching
  4. Show loading states: Display spinners while loading next page
  5. Handle errors gracefully: Network failures shouldn’t break the entire list
Always handle the case where nextPage is null, indicating no more results are available.

Next Steps

  • Use GetIntent to fetch full details when user clicks on an intent
  • Use GetIntentReceipt to show detailed transaction information
  • Implement search/filter functionality on top of pagination
  • Add real-time updates using WaitIntentReceipt for pending intents

Authorizations

X-Access-Key
string
header
required

API Key for authenticating requests, get an access key at https://trails.build and request early access

Body

application/json
page
object
byProjectId
number
byOwnerAddress
string

Response

Successful response

intents
object[]
required

[]IntentSummary

nextPage
object