v1.0
API Reference
Integrate baref00t.io into your stack. Manage customers, trigger assessments, and automate security workflows through the Partner and Distributor APIs.
Overview
baref00t.io exposes two REST APIs that let you automate security assessment workflows. The Partner API is for MSPs who manage their own customers and run assessments against those tenants. The Distributor API is for organisations that provision and manage multiple partner accounts underneath a single billing relationship.
Both APIs accept and return JSON. All requests must be made over HTTPS. HTTP requests are rejected.
Authentication
Every request must include an API key in a custom header. Partner keys and Distributor keys use separate headers and separate prefixes so the server can route your request to the correct API surface.
Partner API Key
Pass your key in the X-Partner-Key header. Partner keys always start with pk_live_.
curl https://api.baref00t.io/api/v1/partner/me \
-H
Distributor API Key
Pass your key in the X-Distributor-Key header. Distributor keys always start with dk_live_.
curl https://api.baref00t.io/api/v1/distributor/me \
-H
Key Management
Each partner account can hold a maximum of two active API keys at any time. Use the Generate API Key and Revoke API Key endpoints to rotate keys with zero downtime: generate a new key in slot 2 while slot 1 is still active, migrate your systems, then revoke slot 1.
Never expose your API key in client-side code, public repositories, or browser requests. Keys carry the same privileges as your partner or distributor account.
Base URLs
| API | Base URL |
| Partner | https://api.baref00t.io/api/v1/partner/ |
| Distributor | https://api.baref00t.io/api/v1/distributor/ |
All endpoint paths in this reference are shown relative to the base URL. For example, GET /v1/partner/me means you send the request to https://api.baref00t.io/api/v1/partner/me.
Rate Limits
| API | Limit | Window |
| Partner | 60 requests | per minute, per key |
| Distributor | 120 requests | per minute, per key |
When you exceed the limit, the API returns a 429 status with the error code RATE_LIMITED. The response includes a Retry-After header indicating how many seconds to wait before retrying.
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Retry after 12 seconds."
}
}
Error Handling
All error responses follow a consistent envelope. The HTTP status code indicates the error category, and the response body contains a machine-readable code and a human-readable message.
{
"error": {
"code": "ERROR_CODE",
"message": "Human readable description of what went wrong."
}
}
Error Codes
| Code | Status | Description |
| MISSING_KEY | 401 | No API key header was provided in the request. |
| INVALID_KEY | 401 | The API key is malformed, expired, or revoked. |
| RATE_LIMITED | 429 | You have exceeded the rate limit for your API tier. |
| PARTNER_INACTIVE | 403 | The partner account is suspended or pending activation. |
| DISTRIBUTOR_INACTIVE | 403 | The distributor account is suspended or pending activation. |
| INVALID_JSON | 400 | The request body is not valid JSON. |
| MISSING_FIELD | 400 | A required field is missing from the request body. |
| INVALID_PRODUCT | 400 | The product identifier is not recognised. |
| PRODUCT_NOT_ALLOWED | 403 | Your plan does not include the requested product. |
| RUN_LIMIT_REACHED | 403 | You have reached the monthly assessment run limit for your plan. |
| NOT_FOUND | 404 | The requested resource does not exist or you do not have access. |
| MAX_KEYS | 409 | You already have the maximum number of API keys (2). |
| TOO_MANY | 400 | The bulk request exceeds the maximum batch size. |
Webhooks
Configure a webhook URL in your partner or distributor portal to receive real-time event notifications. Webhooks are delivered as POST requests with a JSON body to the URL you specify.
Events
assessment.started An assessment run has been queued and is beginning execution.
assessment.completed An assessment run has finished and results are available.
assessment.failed An assessment run encountered an error and could not complete.
customer.created A new customer record was created.
customer.updated A customer record was modified.
customer.deleted A customer record was removed.
partner.activated A sub-partner account has been activated (Distributor only).
partner.suspended A sub-partner account has been suspended (Distributor only).
key.created A new API key was generated for the account.
key.revoked An API key was revoked.
Payload Format
{
"id": "evt_a1b2c3d4e5f6",
"type": "assessment.completed",
"timestamp": "2026-04-03T08:15:22Z",
"data": {
"assessmentId": "run_x9y8z7w6",
"customerId": "cust_abc123",
"product": "essential-eight",
"status": "completed",
"score": 72
}
}
Signature Verification
Every webhook request includes a X-Baref00t-Signature header containing an HMAC-SHA256 signature of the raw request body. Verify this signature using the webhook secret displayed in your portal to ensure the request originated from baref00t.io.
expected = HMAC-SHA256(webhook_secret, raw_request_body)
received = request.headers["X-Baref00t-Signature"]
valid = constant_time_equal(expected, received)
Delivery
Webhooks are delivered with a timeout of 10 seconds. If your endpoint returns a non-2xx status code or times out, the delivery is retried up to 5 times with exponential backoff (1 min, 5 min, 30 min, 2 hr, 12 hr). After all retries are exhausted, the event is marked as failed in your portal's webhook log.
Your webhook endpoint should return a 200 status code as quickly as possible. Process the event payload asynchronously to avoid timeouts.
Partner API
The Partner API lets MSPs manage customers and run security assessments through a single API key. All endpoints require the X-Partner-Key header.
Returns your partner account profile including plan details, usage counters, and limits.
Response 200
{
"id": "prt_abc123",
"company": "Acme MSP",
"email": "admin@acmemsp.com",
"plan": "professional",
"status": "active",
"usage": {
"month": "2026-04",
"runsUsed": 42,
"runsLimit": 200,
"customersCount": 18
},
"createdAt": "2026-01-15T09:30:00Z"
}
Upgrade or downgrade your MSP subscription plan. Changes take effect immediately on your Stripe subscription with proration — upgrades are charged on the next invoice, downgrades credit the unused portion of the current cycle. The new plan's run limit and allowed products apply to assessments triggered after the response returns.
Request body
{
"plan": "professional", // required: 'starter' | 'professional' | 'enterprise'
"billing": "monthly", // optional: 'monthly' | 'rolling' (annual). Defaults to current.
"currency": "usd" // optional: 'usd' | 'aud' | 'gbp' | 'eur' | 'sgd'. Auto-detected from your current subscription if omitted.
}
Response 200
{
"partnerId": "prt_abc123",
"plan": "professional",
"billing": "monthly",
"currency": "usd",
"runLimit": 100,
"subscriptionStatus": "active",
"currentPeriodEnd": "2026-05-09T00:00:00Z"
}
Errors
400 INVALID_JSON — request body could not be parsed
400 PLAN_CHANGE_FAILED — invalid plan/billing, no active subscription, already on target plan,
or subscription is in a state that cannot be modified (canceled, etc)
401 Missing or invalid X-Partner-Key
500 Price lookup or Stripe API error
Notes
Rate-limited to 10 plan changes per hour per partner. Upgrades/downgrades are audited. Dashboard UI is available on the Billing tab of the partner portal.
Returns the list of products available on your current plan.
Response 200
{
"products": [
{
"id": "essential-eight",
"name": "Essential Eight Assessment",
"category": "compliance",
"estimatedDuration": 180
},
{
"id": "nist-csf",
"name": "NIST CSF Assessment",
"category": "compliance",
"estimatedDuration": 240
}
]
}
Returns all customers belonging to your partner account.
Response 200
{
"customers": [
{
"id": "cust_abc123",
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"createdAt": "2026-02-10T14:00:00Z"
}
]
}
Creates a new customer record linked to your partner account.
Request Body
| Field | Type | | Description |
| name | string | required | Display name for the customer organisation. |
| tenantId | string (GUID) | required | Microsoft 365 tenant ID for the customer. |
| email | string | optional | Primary contact email address. |
| receivers | string[] | optional | Email addresses that receive assessment report notifications. |
| questionnaireRecipients | string[] | optional | Email addresses that receive questionnaire invitations. |
{
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"receivers": ["ciso@contoso.com", "it@contoso.com"],
"questionnaireRecipients": ["ciso@contoso.com"]
}
Response 201
{
"id": "cust_abc123",
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"receivers": ["ciso@contoso.com", "it@contoso.com"],
"questionnaireRecipients": ["ciso@contoso.com"],
"createdAt": "2026-04-03T10:00:00Z"
}
curl Example
curl -X POST https://api.baref00t.io/api/v1/partner/customers \
-H \
-H \
-d '{
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"receivers": ["ciso@contoso.com"],
"questionnaireRecipients": ["ciso@contoso.com"]
}'
Returns full details for a single customer including receiver lists and recent assessment history.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Customer ID (e.g. cust_abc123). |
Response 200
{
"id": "cust_abc123",
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"receivers": ["ciso@contoso.com", "it@contoso.com"],
"questionnaireRecipients": ["ciso@contoso.com"],
"recentRuns": [
{
"id": "run_x9y8z7w6",
"product": "essential-eight",
"status": "completed",
"completedAt": "2026-03-28T14:22:00Z"
}
],
"createdAt": "2026-02-10T14:00:00Z"
}
Updates an existing customer. Send only the fields you want to change. Omitted fields remain unchanged.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Customer ID. |
Request Body
{
"name": "Contoso Corporation",
"receivers": ["ciso@contoso.com", "security@contoso.com"]
}
Response 200
{
"id": "cust_abc123",
"name": "Contoso Corporation",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"receivers": ["ciso@contoso.com", "security@contoso.com"],
"questionnaireRecipients": ["ciso@contoso.com"],
"updatedAt": "2026-04-03T10:05:00Z"
}
Permanently removes a customer and all associated assessment data. This action cannot be undone.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Customer ID. |
Response 204
No content. The customer has been deleted.
Triggers a new assessment run for a customer. The run executes asynchronously; poll the status endpoint or use webhooks to track progress.
Request Body
| Field | Type | | Description |
| customerId | string | required | The customer to run the assessment against. |
| product | string | required | Product identifier (e.g. essential-eight, nist-csf). |
| maturityTarget | number | optional | Target maturity level (1-5). Defaults to the product default. |
{
"customerId": "cust_abc123",
"product": "essential-eight",
"maturityTarget": 3
}
Response 202
{
"id": "run_x9y8z7w6",
"customerId": "cust_abc123",
"product": "essential-eight",
"maturityTarget": 3,
"status": "queued",
"createdAt": "2026-04-03T10:10:00Z"
}
curl Example
curl -X POST https://api.baref00t.io/api/v1/partner/assessments \
-H \
-H \
-d '{
"customerId": "cust_abc123",
"product": "essential-eight",
"maturityTarget": 3
}'
Returns a list of assessment runs. Use query parameters to filter results.
Query Parameters
| Parameter | Type | | Description |
| month | string | optional | Filter by month in YYYY-MM format. |
| product | string | optional | Filter by product identifier. |
| customerId | string | optional | Filter by customer ID. |
Response 200
{
"runs": [
{
"id": "run_x9y8z7w6",
"customerId": "cust_abc123",
"product": "essential-eight",
"status": "completed",
"score": 72,
"createdAt": "2026-04-03T10:10:00Z",
"completedAt": "2026-04-03T10:13:22Z"
}
]
}
curl Example
curl "https://api.baref00t.io/api/v1/partner/assessments?month=2026-04&product=essential-eight" \
-H
Returns the current status and results of a single assessment run.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Assessment run ID (e.g. run_x9y8z7w6). |
Response 200
{
"id": "run_x9y8z7w6",
"customerId": "cust_abc123",
"customerName": "Contoso Ltd",
"product": "essential-eight",
"maturityTarget": 3,
"status": "completed",
"score": 72,
"findings": 14,
"critical": 2,
"high": 5,
"medium": 4,
"low": 3,
"reportUrl": "https://app.baref00t.io/reports/run_x9y8z7w6",
"createdAt": "2026-04-03T10:10:00Z",
"completedAt": "2026-04-03T10:13:22Z"
}
Creates multiple customers in a single request. Maximum 100 customers per request.
Request Body
{
"customers": [
{
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com"
},
{
"name": "Fabrikam Inc",
"tenantId": "a1b2c3d4-5678-9abc-def0-123456789abc",
"email": "admin@fabrikam.com"
}
]
}
Response 201
{
"created": 2,
"failed": 0,
"customers": [
{ "id": "cust_abc123", "name": "Contoso Ltd", "status": "created" },
{ "id": "cust_def456", "name": "Fabrikam Inc", "status": "created" }
]
}
Maximum batch size is 100 customers. Requests exceeding this limit return a TOO_MANY error.
Triggers the same assessment product against multiple customers. Maximum 50 customers per request.
Request Body
| Field | Type | | Description |
| product | string | required | Product identifier to run. |
| customerIds | string[] | required | Array of customer IDs. Max 50. |
| maturityTarget | number | optional | Target maturity level applied to all runs. |
{
"product": "essential-eight",
"customerIds": ["cust_abc123", "cust_def456", "cust_ghi789"],
"maturityTarget": 3
}
Response 202
{
"queued": 3,
"failed": 0,
"runs": [
{ "id": "run_001", "customerId": "cust_abc123", "status": "queued" },
{ "id": "run_002", "customerId": "cust_def456", "status": "queued" },
{ "id": "run_003", "customerId": "cust_ghi789", "status": "queued" }
]
}
Maximum batch size is 50 customer IDs. Requests exceeding this limit return a TOO_MANY error.
Generates a new API key for your partner account. Each account can hold a maximum of 2 active keys.
Request Body
No request body required.
Response 201
{
"slot": 2,
"key": "pk_live_newkey789xyz",
"createdAt": "2026-04-03T10:20:00Z"
}
The full key is only returned once at creation time. Store it securely. You cannot retrieve it again.
Revokes the API key in the specified slot. The key becomes immediately invalid.
Path Parameters
| Parameter | Type | | Description |
| slot | number | required | Key slot to revoke: 1 or 2. |
Response 204
No content. The key has been revoked.
You cannot revoke a key if it is the only active key on the account. Generate a new key first, then revoke the old one.
Distributor API
The Distributor API lets you provision and manage multiple partner accounts under a single billing relationship. All endpoints require the X-Distributor-Key header.
Returns your distributor account profile including plan details and aggregate usage.
Response 200
{
"id": "dist_xyz789",
"company": "Global Security Distribution",
"email": "ops@globalsecdist.com",
"status": "active",
"partnersCount": 12,
"usage": {
"month": "2026-04",
"totalRuns": 384,
"totalCustomers": 156
},
"createdAt": "2025-11-01T08:00:00Z"
}
Returns all sub-partner accounts under your distributor account.
Query Parameters
| Parameter | Type | | Description |
| status | string | optional | Filter by status: active, suspended, pending. |
Response 200
{
"partners": [
{
"id": "prt_abc123",
"company": "Acme MSP",
"email": "admin@acmemsp.com",
"plan": "professional",
"status": "active",
"customersCount": 18,
"createdAt": "2026-01-15T09:30:00Z"
}
]
}
Provisions a new partner account under your distributor. The partner receives an activation email.
Request Body
| Field | Type | | Description |
| email | string | required | Admin email for the new partner account. |
| company | string | required | Company name for the partner. |
| name | string | required | Contact name for the partner admin. |
| plan | string | required | Plan to assign: starter, professional, enterprise. |
| billing | object | required | Billing configuration for the partner. |
| billing.currency | string | required | ISO 4217 currency code: AUD, USD, GBP, EUR, NZD. |
| billing.interval | string | optional | Billing interval: quarterly (default) or annual. |
{
"email": "admin@newmsp.com",
"company": "New MSP Pty Ltd",
"name": "Jane Smith",
"plan": "professional",
"billing": {
"currency": "AUD",
"interval": "quarterly"
}
}
Response 201
{
"id": "prt_new456",
"company": "New MSP Pty Ltd",
"email": "admin@newmsp.com",
"plan": "professional",
"status": "pending",
"billing": {
"currency": "AUD",
"interval": "quarterly"
},
"createdAt": "2026-04-03T11:00:00Z"
}
Returns full details for a sub-partner including current plan, billing, and usage for the current month.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID (e.g. prt_abc123). |
Response 200
{
"id": "prt_abc123",
"company": "Acme MSP",
"email": "admin@acmemsp.com",
"name": "John Doe",
"plan": "professional",
"status": "active",
"billing": {
"currency": "AUD",
"interval": "quarterly"
},
"usage": {
"month": "2026-04",
"runsUsed": 42,
"runsLimit": 200,
"customersCount": 18
},
"createdAt": "2026-01-15T09:30:00Z"
}
Updates a sub-partner's plan or billing configuration. Send only the fields you want to change.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID. |
Request Body
{
"plan": "enterprise",
"billing": {
"interval": "annual"
}
}
Response 200
{
"id": "prt_abc123",
"plan": "enterprise",
"billing": {
"currency": "AUD",
"interval": "annual"
},
"updatedAt": "2026-04-03T11:15:00Z"
}
Activates a pending or suspended partner account. The partner immediately gains access to the API and portal.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID. |
Request Body
No request body required.
Response 200
{
"id": "prt_abc123",
"status": "active",
"activatedAt": "2026-04-03T11:20:00Z"
}
Suspends an active partner account. The partner's API keys are immediately invalidated and portal access is revoked.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID. |
Request Body
No request body required.
Response 200
{
"id": "prt_abc123",
"status": "suspended",
"suspendedAt": "2026-04-03T11:25:00Z"
}
Suspending a partner immediately invalidates all of their API keys. The partner will need to generate new keys after reactivation.
Upgrade or downgrade a sub-partner's MSP subscription plan on their behalf. The partner's Stripe subscription is updated with prorated billing, and the new plan's run limits apply immediately.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID (must belong to this distributor). |
Request body
{
"plan": "enterprise", // required: 'starter' | 'professional' | 'enterprise'
"billing": "rolling", // optional: 'monthly' | 'rolling' (annual). Defaults to partner's current.
"currency": "aud" // optional: 'usd' | 'aud' | 'gbp' | 'eur' | 'sgd'. Auto-detected from partner's current subscription if omitted.
}
Response 200
{
"partnerId": "prt_abc123",
"plan": "enterprise",
"billing": "rolling",
"currency": "aud",
"runLimit": -1, // -1 = unlimited
"subscriptionStatus": "active",
"currentPeriodEnd": "2027-04-09T00:00:00Z"
}
Errors
404 NOT_FOUND — partner does not exist or is not owned by this distributor
400 PLAN_CHANGE_FAILED — invalid plan/billing, no active subscription, already on target plan,
or subscription is in a state that cannot be modified
401 Missing or invalid X-Distributor-Key
500 Price lookup or Stripe API error
Notes
Plan changes against sub-partners are audited under the distributor's ID. If the distributor has StripeBillingEnabled=false, the partner's own Stripe subscription is still updated — revenue-share settlement is tracked separately.
Returns all customers belonging to a specific sub-partner.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID. |
Response 200
{
"customers": [
{
"id": "cust_abc123",
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"createdAt": "2026-02-10T14:00:00Z"
}
]
}
Creates a customer record under a specific sub-partner. The request body is identical to the Partner API's create customer endpoint.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID to create the customer under. |
Request Body
{
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"receivers": ["ciso@contoso.com"],
"questionnaireRecipients": ["ciso@contoso.com"]
}
Response 201
{
"id": "cust_new789",
"name": "Contoso Ltd",
"tenantId": "d4f5a678-1234-5678-9abc-def012345678",
"email": "it@contoso.com",
"receivers": ["ciso@contoso.com"],
"questionnaireRecipients": ["ciso@contoso.com"],
"partnerId": "prt_abc123",
"createdAt": "2026-04-03T11:30:00Z"
}
Triggers an assessment run on behalf of a sub-partner. The request body is identical to the Partner API's trigger assessment endpoint.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID. |
Request Body
{
"customerId": "cust_abc123",
"product": "essential-eight",
"maturityTarget": 3
}
Response 202
{
"id": "run_dist001",
"customerId": "cust_abc123",
"partnerId": "prt_abc123",
"product": "essential-eight",
"status": "queued",
"createdAt": "2026-04-03T11:35:00Z"
}
Returns all assessment runs belonging to a specific sub-partner.
Path Parameters
| Parameter | Type | | Description |
| id | string | required | Partner ID. |
Response 200
{
"runs": [
{
"id": "run_dist001",
"customerId": "cust_abc123",
"product": "essential-eight",
"status": "completed",
"score": 72,
"createdAt": "2026-04-03T11:35:00Z",
"completedAt": "2026-04-03T11:38:44Z"
}
]
}
Returns aggregate usage across all sub-partners for the specified month.
Query Parameters
| Parameter | Type | | Description |
| month | string | optional | Month in YYYY-MM format. Defaults to current month. |
Response 200
{
"month": "2026-04",
"totalPartners": 12,
"activePartners": 10,
"totalCustomers": 156,
"totalRuns": 384,
"byPartner": [
{
"partnerId": "prt_abc123",
"company": "Acme MSP",
"runs": 42,
"customers": 18
},
{
"partnerId": "prt_def456",
"company": "SecureIT Partners",
"runs": 67,
"customers": 24
}
]
}
Provisions multiple partner accounts in a single request. Maximum 50 partners per request.
Request Body
{
"partners": [
{
"email": "admin@mspalpha.com",
"company": "MSP Alpha",
"name": "Alice Wong",
"plan": "professional",
"billing": { "currency": "AUD", "interval": "quarterly" }
},
{
"email": "admin@mspbeta.com",
"company": "MSP Beta",
"name": "Bob Chen",
"plan": "starter",
"billing": { "currency": "USD", "interval": "quarterly" }
}
]
}
Response 201
{
"created": 2,
"failed": 0,
"partners": [
{ "id": "prt_alpha01", "company": "MSP Alpha", "status": "pending" },
{ "id": "prt_beta02", "company": "MSP Beta", "status": "pending" }
]
}
Maximum batch size is 50 partners. Requests exceeding this limit return a TOO_MANY error.