External Interactions¶
This page documents how the app exposes its data to external tooling and how external tooling can interact with it.
REST API¶
All models in this app are exposed via Nautobot's standard REST API at /api/plugins/contracts/. Most are full CRUD; one (CostSnapshot) is read-only.
Endpoints¶
| Endpoint | Methods | Notes |
|---|---|---|
/api/plugins/contracts/service-providers/ |
full CRUD | |
/api/plugins/contracts/contracts/ |
full CRUD | |
/api/plugins/contracts/invoices/ |
full CRUD | |
/api/plugins/contracts/contract-assignments/ |
full CRUD | |
/api/plugins/contracts/contract-attachments/ |
full CRUD | multipart for file upload |
/api/plugins/contracts/invoice-attachments/ |
full CRUD | multipart for file upload |
/api/plugins/contracts/cost-snapshots/ |
list + retrieve only | POST/PATCH/DELETE return 405 Method Not Allowed |
CostSnapshot is read-only by design: snapshots are write-once historical telemetry, captured exclusively by the Capture cost history snapshot Job. Allowing external writes would let tooling rewrite history, defeating the "we used to spend $X with that vendor" use case.
Authentication¶
Token authentication via the standard Nautobot user-token mechanism. Generate a token under your user profile, then pass it as Authorization: Token <token> header.
Example queries¶
TOKEN=your-token-here
BASE=https://nautobot.example.com/api/plugins/contracts
# List contracts expiring in May 2026
curl -ks -H "Authorization: Token $TOKEN" \
"$BASE/contracts/?end_date__year=2026&end_date__month=5"
# Pull cost snapshots for the last month, USD only
curl -ks -H "Authorization: Token $TOKEN" \
"$BASE/cost-snapshots/?currency=USD&snapshot_date__gte=2026-04-09"
# Verify CostSnapshot writes are denied
curl -ks -X POST -H "Authorization: Token $TOKEN" -H "Content-Type: application/json" \
-d '{"snapshot_date":"2026-01-01","currency":"USD"}' \
"$BASE/cost-snapshots/"
# → HTTP 405 Method Not Allowed
FK lookups by natural key¶
The standard Nautobot pattern works: ?provider=Acme%20Networks resolves the ServiceProvider by its natural key (name). For composite natural keys, use double-underscore syntax: ?location__name=HQ.
GraphQL¶
All models with @extras_features("graphql") (every model in this app) are queryable through Nautobot's GraphQL endpoint at /graphql/. The schema is auto-generated from the model + serializer.
{
contracts(end_date__lte: "2026-12-31") {
name
provider { name }
end_date
recurring_cost
billing_period
currency
auto_renew
}
cost_snapshots(currency: "USD") {
snapshot_date
monthly_burn
renewal_90d
active_contract_count
}
}
Bulk CSV Import¶
Migrating from a spreadsheet? Use the standard Nautobot import flow at Contracts → Contracts → Import (or /plugins/contracts/contracts/import/). The page auto-generates a field-reference table from the model + serializer — required vs optional, format hints, FK-by-name lookup syntax.
A working sample lives at development/sample-data/contracts.csv. Format quirks (FK by name, boolean literals as true/false, date format YYYY-MM-DD, billing_period choices) are documented in development/sample-data/README.md.
Webhooks¶
All models in this app have @extras_features("webhooks"), so create / update / delete events can fan out to any HTTP endpoint via Nautobot's standard webhook configuration. Common patterns:
- POST renewal warnings into Slack on Contract update
- Notify an ITSM system when a ContractAssignment is created
- Send a finance team email when a CostSnapshot lands above an anomaly threshold (use the
JobLogEntrywebhook trigger onDetect cost anomaliesruns)
Job Schedulers¶
Five Jobs are registered under the Contracts group:
Check upcoming renewals— read-only renewal alertsFind devices without contract coverage— read-only coverage scanMonthly cost report— read-only burn / forecast / top vendor / gap-count summaryCapture cost history snapshot— writes a CostSnapshot row per currencyDetect cost anomalies— reads snapshots, alerts on jumps
All five are idempotent and side-effect-free except Capture cost history snapshot, which writes one row per (date, currency). Re-running the same day is still safe — the unique constraint plus update_or_create prevents duplicates.
Schedule them via Jobs → Scheduled Jobs → Add.
File Attachments¶
Contract and Invoice support file attachments stored under MEDIA_ROOT/contract_attachments/YYYY/MM/<filename> and invoice_attachments/YYYY/MM/<filename> respectively. The nautobot-media Docker volume persists files across container restarts.
⚠️ Production note: files are NOT included in DB dumps. Production deployments need a separate backup strategy for MEDIA_ROOT, or configure DEFAULT_FILE_STORAGE for S3 / cloud storage and back that up via cloud-provider tooling.