BildOut|Developer Documentation

BildOut API

Build powerful integrations with construction invoicing data. Connect your accounting software, project management tools, or custom applications.

Quick Start

Get started with the BildOut API in just a few steps:

  1. Register your application - Contact us to get your OAuth credentials
  2. Implement OAuth flow - Direct users to authorize your app
  3. Make API calls - Use access tokens to fetch data
  4. Handle webhooks - Subscribe to real-time events

Authentication

The BildOut API uses OAuth 2.0 with the Authorization Code flow. This ensures users explicitly grant access to their data.

Scopes

ScopeDescription
invoices:readRead invoice data
invoices:writeCreate and update invoices
payments:readRead payment data
customers:readRead customer data
customers:writeCreate and update customers
projects:readRead project data
projects:writeCreate and update projects
vendors:readRead vendor data
vendors:writeCreate and update vendors
webhooks:manageManage webhook subscriptions

OAuth Flow

// Using fetch to exchange authorization code
const response = await fetch('https://bildout.com/oauth/token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: authCode,
    redirect_uri: 'https://yourapp.com/callback',
    client_id: process.env.BILDOUT_CLIENT_ID,
    client_secret: process.env.BILDOUT_CLIENT_SECRET,
  }),
});

const { access_token, refresh_token, expires_in } = await response.json();

Rate Limits

API requests are rate limited per access token:

  • Standard: 100 requests per minute
  • Burst: 20 requests per second

Rate limit information is included in response headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1703980800

Invoices

List Invoices

GET /api/v1/invoices

const response = await fetch(
  'https://bildout.com/api/v1/invoices?limit=20&status=sent',
  {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
    },
  }
);

const { data: invoices, pagination } = await response.json();
console.log(`Found ${invoices.length} invoices`);

Create Invoice

POST /api/v1/invoices

const invoice = await fetch('https://bildout.com/api/v1/invoices', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    client_id: customerId,
    due_date: '2025-02-15',
    line_items: [
      {
        name: 'Construction Materials',
        quantity: 100,
        unit_price: 45.00,
        tax_rate: 8.5,
      },
      {
        name: 'Labor - Installation',
        quantity: 16,
        unit_price: 75.00,
      },
    ],
    notes: 'Thank you for your business!',
  }),
}).then(r => r.json());

console.log(`Created invoice: ${invoice.data.invoice_number}`);

Payments

Payments represent money received from customers (incoming) or paid to vendors (outgoing).

Endpoints

  • GET /api/v1/payments - List payments
  • GET /api/v1/payments/:id - Get payment details

Customers

Customers are the people or businesses you invoice for your work.

Endpoints

  • GET /api/v1/customers - List customers
  • POST /api/v1/customers - Create customer
  • GET /api/v1/customers/:id - Get customer
  • PUT /api/v1/customers/:id - Update customer
  • DELETE /api/v1/customers/:id - Delete customer

Projects

Projects represent construction jobs. Link invoices and payments to projects for detailed financial tracking.

Endpoints

  • GET /api/v1/projects - List projects
  • POST /api/v1/projects - Create project
  • GET /api/v1/projects/:id - Get project
  • PUT /api/v1/projects/:id - Update project
  • DELETE /api/v1/projects/:id - Delete project
  • GET /api/v1/projects/:id/financials - Get financial summary

Vendors

Vendors are suppliers, subcontractors, and consultants you pay for materials and services.

Endpoints

  • GET /api/v1/vendors - List vendors
  • POST /api/v1/vendors - Create vendor
  • GET /api/v1/vendors/:id - Get vendor
  • PUT /api/v1/vendors/:id - Update vendor
  • DELETE /api/v1/vendors/:id - Delete vendor

Webhooks

Webhooks notify your application in real-time when events occur in BildOut. Subscribe to specific events to keep your systems in sync.

Event Types

Invoices

  • invoice.created
  • invoice.updated
  • invoice.sent
  • invoice.paid
  • invoice.deleted

Payments

  • payment.received
  • payment.sent

Customers

  • customer.created
  • customer.updated
  • customer.deleted

Projects

  • project.created
  • project.updated
  • project.deleted

Verifying Signatures

All webhook payloads are signed with HMAC-SHA256. Always verify signatures before processing webhooks.

import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signatureHeader: string,
  secret: string
): boolean {
  // Parse header: t=timestamp,v1=signature
  const parts = signatureHeader.split(',');
  const timestamp = parts.find(p => p.startsWith('t='))?.slice(2);
  const signature = parts.find(p => p.startsWith('v1='))?.slice(3);

  if (!timestamp || !signature) return false;

  // Check timestamp is recent (within 5 minutes)
  const age = Math.abs(Date.now() / 1000 - parseInt(timestamp));
  if (age > 300) return false;

  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  // Constant-time comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature, 'hex'),
    Buffer.from(expected, 'hex')
  );
}

Error Handling

The API uses standard HTTP status codes and returns JSON error responses:

{
  "error": {
    "code": "validation_error",
    "message": "Invalid request parameters",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ],
    "request_id": "req_abc123xyz"
  }
}

Error Codes

StatusCodeDescription
400invalid_requestMalformed request
401unauthorizedInvalid or expired token
403insufficient_scopeToken lacks required scope
404not_foundResource not found
422validation_errorInvalid field values
429rate_limit_exceededToo many requests
500server_errorInternal server error