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/jsonPATs 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.
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.
| Scope | Grants |
|---|---|
read:projects | Read project metadata, files, and status. |
write:projects | Create projects and upload files. |
read:quotes | Read quote configurations and pricing. |
write:quotes | Submit quote requests. |
read:invoices | Read invoices and payment status. |
write:invoices | Mark invoices as paid externally (where supported). |
read:inbox | Read inbox notifications. |
write:inbox | Mark inbox notifications as read. |
read:cad | List and download CAD Cloud files. |
write:cad | Upload to CAD Cloud. |
read:webhooks | List webhook subscriptions and deliveries. |
write:webhooks | Create, edit, and delete webhook subscriptions. |
admin:account | Read 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.
| Event | When it fires |
|---|---|
quote.ready | A new quote is ready for the customer to review. |
order.placed | The customer accepted a quote and the order is confirmed. |
order.production_started | Manufacturing has started on an order. |
order.shipped | The carrier has picked up the order. |
order.delivered | The order was delivered to its destination. |
invoice.issued | A new invoice was issued. |
invoice.due_soon | An invoice is within 72 hours of its due date. |
invoice.paid | An invoice was paid. |
invoice.overdue | An invoice is past its due date. |
ncr.issued | A quality flag (NCR) was raised on a part. |
ncr.resolved | A quality flag was resolved. |
message.reply | Staff replied on a project-scoped message thread. |
message.general_reply | Staff replied on your general (account-level) thread. |
security.password_changed | The account password was changed. |
security.2fa_enabled | Two-factor authentication was enabled. |
security.2fa_disabled | Two-factor authentication was disabled. |
security.new_login | A new sign-in occurred on the account. |
account.deleted | The account was deleted. |
webhook.test | A 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).
X-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:
| Attempt | Wait before next try |
|---|---|
| 1 | 30 seconds |
| 2 | 2 minutes |
| 3 | 10 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours |
| 7 | 24 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
- Open the Developers dashboard to mint a token and register your first webhook.
- Run an end-to-end test by clicking Send test on a subscription — the scheduled delivery worker fires it on the next tick (≤ 60 s).
- Check Fabdigit status during incidents to see real-time API + database probe results.