Build on Fabdigit

The developer reference

Wire your ERP, accounting, CI, or Slack into Fabdigit. This page covers everything you need to mint an access token, register a webhook, and verify the signed payloads we send back.

Authentication

The Fabdigit API accepts two kinds of bearer tokens. The web dashboard signs you in with a session JWT that lives in an HTTP-only cookie. For scripts, CI jobs, and machine-to-machine integrations, use a Personal Access Token (PAT) minted from your Developers dashboard.

Pass the token in the Authorization header on every request:

GET /projects HTTP/1.1
Host: api.fabdigit.com
Authorization: Bearer pat_4f6c81ad6b8e5b1c1c0c2dd0a2f5e914c8a3d6f0b8c0d8d8d8d8d8d8d8d8d8d8d
Accept: application/json

PATs are 64-character hex secrets prefixed with pat_. The prefix is load-bearing: it lets GitHub-style secret-scanners detect a leaked token in a public repo, and it tells the Fabdigit auth layer which verifier to use.

Treat tokens like passwords. Anyone with your PAT can act as you within its scopes. If a token leaks, rotate or revoke it immediately from the Developers dashboard — we cannot recover a leaked secret.

Scopes

When you create a PAT you choose which scopes it carries. Leaving the list empty grants full account scope (parity with your web session) — useful for tokens intended only for short-lived debugging.

ScopeGrants
read:projectsRead project metadata, files, and status.
write:projectsCreate projects and upload files.
read:quotesRead quote configurations and pricing.
write:quotesSubmit quote requests.
read:invoicesRead invoices and payment status.
write:invoicesMark invoices as paid externally (where supported).
read:inboxRead inbox notifications.
write:inboxMark inbox notifications as read.
read:cadList and download CAD Cloud files.
write:cadUpload to CAD Cloud.
read:webhooksList webhook subscriptions and deliveries.
write:webhooksCreate, edit, and delete webhook subscriptions.
admin:accountRead your account profile (does NOT grant write).

Webhooks

Webhooks push lifecycle events from Fabdigit to your endpoint as they happen. Each subscription is owned by one customer account, targets one HTTPS URL, and can listen to a curated list of event types (or all of them).

We POST a JSON envelope and include a few headers your handler can dedupe and authenticate against:

POST /webhooks/fabdigit HTTP/1.1
Host: hooks.example.com
Content-Type: application/json
User-Agent: FabDigit-Webhook/1
X-FabDigit-Signature: sha256=8c4f9...
X-FabDigit-Signature-Fingerprint: 7a1e8c2b9f12
X-FabDigit-Timestamp: 1747356000
X-FabDigit-Event-Id: 91428
X-FabDigit-Event-Type: order.shipped
X-FabDigit-Audience: customer

{
  "id": 91428,
  "type": "order.shipped",
  "user_id": 1024,
  "created_at": "2026-05-15T11:00:00.000Z",
  "is_test": false,
  "data": {
    "title": "Your order shipped",
    "message": "Tracking #1Z123…",
    "project_no": "P-20260515-0001"
  }
}

Event types

The taxonomy below is the complete list. Subscribing to an empty list means “all events”. We add new event types over time; the existing names are stable.

EventWhen it fires
quote.readyA new quote is ready for the customer to review.
order.placedThe customer accepted a quote and the order is confirmed.
order.production_startedManufacturing has started on an order.
order.shippedThe carrier has picked up the order.
order.deliveredThe order was delivered to its destination.
invoice.issuedA new invoice was issued.
invoice.due_soonAn invoice is within 72 hours of its due date.
invoice.paidAn invoice was paid.
invoice.overdueAn invoice is past its due date.
ncr.issuedA quality flag (NCR) was raised on a part.
ncr.resolvedA quality flag was resolved.
message.replyStaff replied on a project-scoped message thread.
message.general_replyStaff replied on your general (account-level) thread.
security.password_changedThe account password was changed.
security.2fa_enabledTwo-factor authentication was enabled.
security.2fa_disabledTwo-factor authentication was disabled.
security.new_loginA new sign-in occurred on the account.
account.deletedThe account was deleted.
webhook.testA test delivery sent from the dashboard.

Verifying signatures

Every webhook delivery is signed with HMAC-SHA256 using the subscription's per-endpoint signing secret. Re-compute the signature on your side and reject any request whose computed hex doesn't match the X-FabDigit-Signature header.

import crypto from 'node:crypto';

export function verifyFabdigitSignature(rawBody, headers, secret) {
  const sig = String(headers['x-fabdigit-signature'] || '');
  if (!sig.startsWith('sha256=')) return false;
  const provided = sig.slice('sha256='.length);

  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');

  // timingSafeEqual to defend against timing-based recovery.
  return (
    provided.length === expected.length &&
    crypto.timingSafeEqual(
      Buffer.from(provided, 'hex'),
      Buffer.from(expected, 'hex')
    )
  );
}

The rawBody must be the exact bytes we sent — re-serializing the JSON in your handler before verifying will produce a mismatch (different key order, whitespace, or numeric precision).

Rotate signing secrets from the Developers dashboard whenever a teammate leaves or a deploy environment changes. The fingerprint headerX-FabDigit-Signature-Fingerprint lets your verifier roll over by accepting both old and new keys for a short window.

Retry policy & circuit breaker

Deliveries that fail (transport error, timeout > 10 s, or any non-2xx HTTP status) are retried with the following backoff:

AttemptWait before next try
130 seconds
22 minutes
310 minutes
430 minutes
52 hours
66 hours
724 hours
8— (delivery marked dead)

A subscription that records 10 consecutive failures is auto-paused (“disabled”). Re-enable it from the Developers dashboard once you've fixed the receiving endpoint.

We treat HTTP 2xx as success. Return early from your handler (e.g. enqueue then ack) so a downstream issue in your system doesn't cause Fabdigit to retry unnecessarily.

Next steps

Developers · Fabdigit | FabDigit