Skip to main content
This guide is for customers with existing custody infrastructure who want full programmatic control over yield operations. If you have your own custody solution (HSM, MPC, homegrown infrastructure) and want to integrate with RebelFi APIs, this is your path.

Who This Is For

  • Crypto-native companies with existing custody infrastructure
  • Institutional investors with security policies requiring custom signing
  • Wallet providers integrating yield into their existing platform
  • Payment processors with operational wallet infrastructure
Key Characteristic: You want to run your own agent that polls RebelFi for unsigned transactions, signs them with your custody, and reports back execution status.
Alternative Approaches: If you prefer RebelFi to manage the agent, see Custody Adapters. If you use Fireblocks/BitGo directly, consider Direct API Integration.

Architecture Overview

The Complete Flow

1. Customer Funds → Your Custody Wallet
2. RebelFi Detects Idle Funds → Creates Operation
3. You Query Pending Operations
4. You Approve Operation
5. Your Agent Polls for Unsigned Transaction
6. Your Custody Signs Transaction
7. Your Agent Reports Execution
8. RebelFi Monitors Blockchain Confirmation
9. Allocation Active, Earning Yield

Key Integration Points

StepAPI EndpointYour Responsibility
Account SetupPOST /api/core/auth/*One-time registration
Custody ConfigPOST /api/core/custody/setup/third-partyConfigure platform
API KeysPOST /api/core/apikeys/generateGenerate and store securely
Wallet ImportPOST /api/core/org-walletsProvide wallet address
Enable MonitoringPOST /api/core/wallets/add-and-monitorSet buffer amount
Approve OperationsPOST /api/core/operations/:id/approveProgrammatic approval
Poll for WorkPOST /api/agent/transactions/pollYour agent calls every 10-30s
Sign TransactionYour Custody APIYour signing infrastructure
Report ExecutionPOST /api/agent/transactions/:id/reportYour agent reports txHash
The three bolded rows are where your custom agent integrates. Everything else is standard API usage.

Phase 1: Account Setup (One-Time)

Step 1.1: Register Email

POST /api/core/auth/register-email
Content-Type: application/json

{
  "email": "treasury@yourcompany.com"
}
Response:
{
  "success": true,
  "message": "Verification code sent to email"
}
You’ll receive a 6-digit verification code via email.

Step 1.2: Verify Email

POST /api/core/auth/verify-email
Content-Type: application/json

{
  "email": "treasury@yourcompany.com",
  "code": "123456"  // From email
}
Response:
{
  "success": true,
  "verified": true
}

Step 1.3: Complete Registration

POST /api/core/auth/register
Content-Type: application/json

{
  "firstName": "Treasury",
  "lastName": "Team",
  "email": "treasury@yourcompany.com",
  "password": "SecurePassword123!",
  "clientType": "WEB"
}
Response:
{
  "success": true,
  "data": {
    "user": { "id": 1, "email": "..." },
    "session": { "accessToken": "...", "refreshToken": "..." }
  }
}
Store the accessToken securely. You’ll need it for subsequent API calls that require JWT authentication (dashboard-style endpoints).

Step 1.4: Configure Custody Platform

Tell RebelFi you’re using a third-party custody solution:
POST /api/core/custody/setup/third-party
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "custodyPlatform": "REBELFI_AGENT",  // For custom agents
  "supportedChains": ["SOLANA"]        // Blockchains you support
}
Response:
{
  "success": true,
  "data": {
    "platform": "REBELFI_AGENT",
    "chains": ["SOLANA"]
  }
}
Use "REBELFI_AGENT" as the platform name when you’re running your own custom polling agent.

Phase 2: Generate API Keys

API keys are required for agent polling endpoints.
POST /api/core/apikeys/generate
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "name": "Production Agent"
}
Response:
{
  "success": true,
  "data": {
    "id": 1,
    "key": "rfk_live_xxxxxxxxxxxxxxxxxxxxx",
    "name": "Production Agent",
    "createdAt": "2025-01-30T10:00:00Z"
  }
}
Critical: Save the key value immediately. It will only be shown once. This is your X-API-Key for agent polling.
export REBELFI_API_KEY="rfk_live_xxxxxxxxxxxxxxxxxxxxx"

Phase 3: Import and Monitor Wallets

Step 3.1: Import Wallet

Import your custody wallet address into RebelFi:
POST /api/core/org-wallets
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "chainName": "SOLANA",
  "name": "Treasury Wallet",
  "address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"
}
Response:
{
  "success": true,
  "data": {
    "id": 123,  // This is your orgWalletId
    "address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
    "chainName": "SOLANA",
    "name": "Treasury Wallet"
  }
}

Step 3.2: Enable Yield Monitoring

Enable RebelFi to monitor this wallet for yield opportunities:
POST /api/core/wallets/add-and-monitor
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "orgWalletId": 123,
  "enableYield": true,
  "bufferAmount": "100000"  // Base units: 0.1 USDC buffer
}
Response:
{
  "success": true,
  "data": {
    "managedWallet": {
      "id": 456,  // This is your opWalletId
      "orgWalletId": 123,
      "enableYield": true,
      "bufferAmountBase": "100000"
    },
    "wallet": {
      "id": 789,
      "address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"
    }
  }
}
Buffer Amount: Funds kept liquid (not deployed to yield). Set to your minimum operational liquidity requirement.
  • bufferAmount is in base units (e.g., 100000 = 0.1 USDC for 6 decimals)
  • Funds above buffer are automatically eligible for yield deployment

Phase 4: Auto-Supply Flow (When Funds Arrive)

What Happens Automatically

When funds arrive in your wallet:
  1. RebelFi Monitoring detects the inflow
  2. Operation Auto-Created (type: SUPPLY, status: PENDING_APPROVAL)
  3. Your workflow takes over
RebelFi only creates operations for funds above your buffer amount. If you have a 0.1 USDC buffer and receive 1.0 USDC, a SUPPLY operation will be created for ~0.9 USDC.

Step 4.1: Query Pending Operations

Check for operations needing approval:
GET /api/core/operations/queue
Authorization: Bearer YOUR_ACCESS_TOKEN
Response:
{
  "success": true,
  "data": {
    "intents": [
      {
        "id": 789,
        "type": "SUPPLY",
        "status": "PENDING_APPROVAL",
        "managedWalletId": 456,
        "amount": "900000",  // Base units: 0.9 USDC
        "token": "USDC",
        "estimatedAPY": "6.5%",
        "createdAt": "2025-01-30T14:00:00Z"
      }
    ]
  }
}
Authentication Note: This endpoint currently requires JWT (Authorization: Bearer) authentication, not API key (X-API-Key). Planned enhancement: API key support coming soon.

Step 4.2: Approve Operation

Programmatically approve the operation:
POST /api/core/operations/789/approve
Authorization: Bearer YOUR_ACCESS_TOKEN
Response:
{
  "success": true,
  "data": {
    "id": 789,
    "status": "EXECUTING",
    "approvedAt": "2025-01-30T14:01:00Z"
  }
}
Once approved, the operation enters the EXECUTING state and is ready for your agent to pick up.
Policy Configuration: You can configure your organization to auto-approve certain operations (below threshold, specific wallets, etc.). Contact support or configure in Settings → Operation Policies.

Phase 5: Agent Polling & Execution (Your Custom Agent)

This is where your custom agent takes control.

Step 5.1: Poll for Unsigned Transactions

Your agent should poll every 10-30 seconds:
POST /api/agent/transactions/poll
X-API-Key: rfk_live_xxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "leaseDurationMs": 30000  // 30 seconds
}
Response (Transaction Available):
{
  "success": true,
  "data": {
    "transaction": {
      "id": 4001,
      "attemptId": 5001,
      "operationId": 789,
      "unsignedTx": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAHEAoMCg...",
      "metadata": {
        "blockchain": "SOLANA",
        "walletId": 456,
        "amount": "900000",
        "token": "USDC",
        "type": "SUPPLY"
      },
      "claimedAt": "2025-01-30T14:01:00Z",
      "leaseExpiresAt": "2025-01-30T14:01:30Z"
    }
  }
}
Response (No Work Available):
{
  "success": true,
  "data": {
    "transaction": null
  }
}
Lease Mechanism: When you poll and receive a transaction, it’s “claimed” for leaseDurationMs milliseconds. If you don’t report within that time, the lease expires and another agent can claim it.Set leaseDurationMs longer than your signing + submission time. Typical values: 30-60 seconds.

Step 5.2: Sign Transaction with Your Custody

This is your custom custody integration. Examples:
  • Custom HSM
  • MPC Wallet
  • Smart Contract Wallet
// Your custom HSM signing
const signedTx = await yourHSM.sign({
  unsignedTransaction: transaction.unsignedTx,
  walletAddress: transaction.metadata.walletAddress,
  keyId: 'your-key-id'
});

Step 5.3: Submit to Blockchain

After signing, submit to the blockchain:
import { Connection } from '@solana/web3.js';

const connection = new Connection('https://api.mainnet-beta.solana.com');

const txHash = await connection.sendRawTransaction(
  Buffer.from(signedTx, 'base64')
);

console.log('Transaction submitted:', txHash);

Step 5.4: Report Execution to RebelFi

Report the transaction hash back to RebelFi:
POST /api/agent/transactions/5001/report
X-API-Key: rfk_live_xxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "attemptId": 5001,
  "status": "SUCCESS",
  "result": {
    "txHash": "5aApzp1XxiNzFotAiZt6z7BaTTYCS7964ycpxwYp4eVyxentgDcevD12pKoT7qHUakoBnp3nZPqrXz4479FZs59J",
    "submissionMode": "AGENT"
  }
}
Response:
{
  "success": true,
  "data": {
    "attemptId": 5001,
    "status": "SUBMITTED",
    "txHash": "5aApzp...",
    "reportedAt": "2025-01-30T14:01:15Z"
  }
}
Reporting Failures: If signing or submission fails, report with status: "FAILED" and include an error message:
{
  "attemptId": 5001,
  "status": "FAILED",
  "result": {
    "error": "Insufficient SOL for transaction fees"
  }
}

Phase 6: RebelFi Monitors Completion

After you report the transaction:
  1. RebelFi monitors blockchain for confirmation
  2. Operation completes when transaction confirms
  3. Allocation created (funds now earning yield)
  4. Available balance updated (funds moved from available → allocated)
You can query the operation status:
GET /api/core/operations/789
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (Completed):
{
  "success": true,
  "data": {
    "id": 789,
    "type": "SUPPLY",
    "status": "COMPLETED",
    "completedAt": "2025-01-30T14:02:30Z",
    "txHash": "5aApzp..."
  }
}

Phase 7: Query Yield Metrics (Roadmap)

Current Status: Yield metrics APIs are planned but not yet available with API key authentication. Use the dashboard for now.
Planned Endpoints:
// Token positions with yield breakdown
GET /api/token-positions/op-wallet/:id
X-API-Key: rfk_live_xxxxxxxxxxxxxxxxxxxxx

// Would return:
{
  "balances": {
    "total": { "amount": "1.11", "currency": "USDC" },
    "principal": { "amount": "1.10", "currency": "USDC" },
    "yield": { "amount": "0.01", "currency": "USDC" }
  },
  "performance": {
    "currentAPY": "6.0",
    "lifetimeYield": { "amount": "0.01", "currency": "USDC" }
  }
}
See Yield Metrics API for planned features.

Phase 8: Disburse Flow (Withdraw Funds)

To withdraw funds from yield back to your wallet:

Step 8.1: Create Disburse Operation

POST /api/core/wallets/transfer-out
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "walletId": 789,
  "tokenMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",  // USDC
  "amount": "0.5",  // Decimal format
  "destinationAddress": "YourDestinationWalletAddress..."
}
Response:
{
  "success": true,
  "data": {
    "operationId": 790,
    "type": "DISBURSE",
    "status": "PENDING_APPROVAL"
  }
}

Step 8.2: Follow Same Flow

The disburse operation follows the exact same flow as supply:
  1. Query operations queue → See DISBURSE operation
  2. Approve operation → POST /api/core/operations/790/approve
  3. Agent polls → Receives UNWIND + TRANSFER transaction
  4. Sign with your custody → Same signing process
  5. Report execution → POST /api/agent/transactions/:id/report
  6. RebelFi monitors completion
Disburse operations often have two steps in a single transaction:
  1. UNWIND - Withdraw from yield protocol
  2. TRANSFER_OUT - Send to destination address
Your agent receives these as a single atomic transaction to sign.

Complete Agent Implementation Example

Here’s a complete polling agent implementation:
import axios from 'axios';
import { Connection } from '@solana/web3.js';
import { yourCustodySolution } from './custody';

const agent = axios.create({
  baseURL: process.env.REBELFI_BASE_URL,
  headers: { 'X-API-Key': process.env.REBELFI_API_KEY }
});

const solanaConnection = new Connection(process.env.SOLANA_RPC_URL);

async function pollAndExecute() {
  try {
    // 1. Poll for transaction
    const { data } = await agent.post('/api/agent/transactions/poll', {
      leaseDurationMs: 30000
    });

    if (data.data.transaction) {
      const tx = data.data.transaction;
      console.log(`Claimed transaction ${tx.id} for operation ${tx.operationId}`);

      try {
        // 2. Sign with your custody
        const signedTx = await yourCustodySolution.sign({
          unsignedTx: tx.unsignedTx,
          metadata: tx.metadata
        });

        // 3. Submit to blockchain
        const txHash = await solanaConnection.sendRawTransaction(
          Buffer.from(signedTx, 'base64')
        );

        console.log(`Transaction submitted: ${txHash}`);

        // 4. Report success
        await agent.post(`/api/agent/transactions/${tx.id}/report`, {
          attemptId: tx.attemptId,
          status: 'SUCCESS',
          result: {
            txHash: txHash,
            submissionMode: 'AGENT'
          }
        });

        console.log(`Transaction ${tx.id} reported successfully`);
      } catch (error) {
        // Report failure
        console.error('Execution error:', error);
        await agent.post(`/api/agent/transactions/${tx.id}/report`, {
          attemptId: tx.attemptId,
          status: 'FAILED',
          result: {
            error: error.message
          }
        });
      }
    } else {
      console.log('No transactions available');
    }
  } catch (error) {
    console.error('Polling error:', error);
  }
}

// Main loop
async function main() {
  console.log('Starting RebelFi custom agent...');

  while (true) {
    await pollAndExecute();
    await new Promise(resolve => setTimeout(resolve, 10000)); // Poll every 10 seconds
  }
}

main();

Error Handling & Best Practices

Handling Lease Expiry

If your agent crashes or takes too long, the lease expires:
// Best practice: Set lease longer than signing time
const AVERAGE_SIGNING_TIME = 5000; // 5 seconds
const NETWORK_LATENCY = 2000;      // 2 seconds
const LEASE_DURATION = (AVERAGE_SIGNING_TIME + NETWORK_LATENCY) * 3; // 21 seconds buffer

await agent.post('/api/agent/transactions/poll', {
  leaseDurationMs: LEASE_DURATION
});

Retry Logic

async function pollWithRetry(maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await pollAndExecute();
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;

      const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Monitoring Agent Health

const metrics = {
  lastPollAt: null,
  lastExecutionAt: null,
  successCount: 0,
  failureCount: 0
};

// Expose health endpoint
app.get('/health', (req, res) => {
  const isHealthy =
    metrics.lastPollAt &&
    (Date.now() - metrics.lastPollAt.getTime()) < 60000;

  res.json({
    status: isHealthy ? 'healthy' : 'unhealthy',
    metrics: {
      lastPollAt: metrics.lastPollAt,
      lastExecutionAt: metrics.lastExecutionAt,
      successRate: (metrics.successCount / (metrics.successCount + metrics.failureCount) * 100).toFixed(2) + '%'
    }
  });
});

Deployment Considerations

Infrastructure Requirements

  • Compute: Lightweight (polling loop, signing, API calls)
  • Network: Outbound HTTPS to api.rebelfi.io and blockchain RPC
  • Secrets: Secure storage for API keys and custody credentials
  • Uptime: High availability recommended (operations wait for your agent)

Deployment Options

  • Docker
  • Kubernetes
  • Systemd
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --production

COPY . .

CMD ["node", "agent.js"]
docker run -d \
  --name rebelfi-agent \
  --env-file .env \
  --restart unless-stopped \
  your-agent-image:latest

Security Best Practices

  • Store API keys in secrets manager (AWS Secrets Manager, HashiCorp Vault)
  • Never log API keys in plain text
  • Rotate API keys periodically (every 90 days recommended)
  • Use different API keys for dev/staging/production
  • Store custody credentials encrypted at rest
  • Use hardware security modules (HSM) where possible
  • Implement least-privilege access for agent service accounts
  • Audit all signing operations
  • Run agent in private network segment
  • Restrict outbound traffic to RebelFi API and blockchain RPC only
  • Use TLS for all communications
  • Consider VPN or private link for additional security
  • Run agent with automatic restart (Docker, systemd, K8s)
  • Monitor agent health and alert on failures
  • The lease mechanism prevents duplicate execution even with multiple agents
  • Implement dead letter queue for failed transactions

Troubleshooting

Symptoms: No logs showing poll attemptsCheck:
  • Agent process is running
  • Network connectivity to api.rebelfi.io
  • API key is valid (X-API-Key header)
  • Environment variables loaded correctly
Solution:
# Test API connectivity
curl https://api.rebelfi.io/api/agent/transactions/poll \
  -X POST \
  -H "X-API-Key: $REBELFI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"leaseDurationMs": 30000}'
Symptoms: Funds in wallet but no operations createdCheck:
  • Funds are above buffer amount
  • Wallet monitoring is enabled
  • No other operation is currently in progress (wallet-level locking)
Solution: Query wallet status:
GET /api/core/wallets/monitored
Symptoms: Agent reports “FAILED” status repeatedlyCheck:
  • Custody credentials are valid
  • Custody service is reachable
  • Transaction format is correct for your custody solution
  • Sufficient gas/fees in wallet
Solution: Review custody logs for specific error messages
Symptoms: Transactions repeatedly claimed but never completedCheck:
  • leaseDurationMs is longer than signing + submission time
  • Network latency to custody provider
  • Agent isn’t crashing during execution
Solution: Increase lease duration to 60000ms (60 seconds) or monitor signing performance

Next Steps


Support

Need help with your custom custody integration?