OpenGRC API Documentation
Overview
The OpenGRC API provides RESTful endpoints for managing all resources in the GRC system. All endpoints require authentication via Laravel Sanctum tokens and respect the permission system based on user roles.
Authentication
Generate API Token
Users can generate API tokens from the Filament admin panel using the built-in Sanctum token management (Filament Breezy).
- Log in to the OpenGRC web interface
- Navigate to your profile settings
- Generate a new API token
- Copy the token (it will only be shown once)
Using the Token
Include the token in all API requests using the Authorization header:
Authorization: Bearer YOUR_TOKEN_HERE
Rate Limiting
API requests are rate-limited to 60 requests per minute per user (or IP address for unauthenticated requests).
Rate limit headers are included in all responses:
- X-RateLimit-Limit: Maximum requests allowed
- X-RateLimit-Remaining: Remaining requests in current window
- Retry-After: Seconds to wait before retrying (when rate limited)
Permissions
All endpoints check permissions using the Spatie Permission system. Required permissions follow this pattern:
GET /api/resources→List {Resources}permissionPOST /api/resources→Create {Resources}permissionGET /api/resources/{id}→Read {Resources}permissionPUT/PATCH /api/resources/{id}→Update {Resources}permissionDELETE /api/resources/{id}→Delete {Resources}permission
If a user lacks the required permission, the API returns a 403 Forbidden response.
Common Query Parameters
Pagination
All index endpoints support pagination:
per_page- Number of results per page (default: 15, max: 100)page- Page number (default: 1)no_pagination- Set totrueto disable pagination and return all results
Example:
GET /api/standards?per_page=25&page=2
Searching
Search across searchable fields:
search- Search term to filter results
Example:
GET /api/controls?search=encryption
Sorting
Sort results by any sortable field:
sort- Field name to sort bydirection- Sort direction (ascordesc)
Example:
GET /api/audits?sort=created_at&direction=desc
Eager Loading
Load relationships using the with parameter:
GET /api/controls/1?with=standard,implementations
Available Endpoints
Users
Base URL: /api/users
GET /api/users- List all usersPOST /api/users- Create a new userGET /api/users/{id}- Get a specific userPUT /api/users/{id}- Update a userDELETE /api/users/{id}- Delete a user (soft delete)POST /api/users/{id}/restore- Restore a soft-deleted user
Searchable Fields: name, email
Relations: roles, permissions, managedPrograms
Required Permissions: - Only users with "Manage Users" permission can access these endpoints - Password must meet security requirements: minimum 12 characters, mixed case, not previously compromised
Create User Request:
{
"name": "John Doe",
"email": "[email protected]",
"password": "SecurePassword123!",
"password_confirmation": "SecurePassword123!",
"roles": ["Regular User"]
}
Update User Request:
{
"name": "Jane Doe",
"email": "[email protected]",
"roles": ["Security Admin", "Internal Auditor"]
}
Notes:
- Passwords are hashed automatically using Laravel's secure hashing
- Password confirmation is required when creating or updating passwords
- Roles can be assigned/updated via the roles array
- Sensitive fields (password, remember_token) are hidden in responses
- Users are soft-deleted by default
Standards
Base URL: /api/standards
GET /api/standards- List all standardsPOST /api/standards- Create a new standardGET /api/standards/{id}- Get a specific standardPUT /api/standards/{id}- Update a standardDELETE /api/standards/{id}- Delete a standardPOST /api/standards/{id}/restore- Restore a soft-deleted standard
Searchable Fields: code, title, description
Relations: controls, programs
Controls
Base URL: /api/controls
GET /api/controls- List all controlsPOST /api/controls- Create a new controlGET /api/controls/{id}- Get a specific controlPUT /api/controls/{id}- Update a controlDELETE /api/controls/{id}- Delete a controlPOST /api/controls/{id}/restore- Restore a soft-deleted control
Searchable Fields: identifier, title, description, standard.code, standard.title
Relations: standard, implementations, controlOwner
Implementations
Base URL: /api/implementations
GET /api/implementations- List all implementationsPOST /api/implementations- Create a new implementationGET /api/implementations/{id}- Get a specific implementationPUT /api/implementations/{id}- Update an implementationDELETE /api/implementations/{id}- Delete an implementationPOST /api/implementations/{id}/restore- Restore a soft-deleted implementation
Searchable Fields: title, details, notes
Relations: controls, risks, assets, implementationOwner
Audits
Base URL: /api/audits
GET /api/audits- List all auditsPOST /api/audits- Create a new auditGET /api/audits/{id}- Get a specific auditPUT /api/audits/{id}- Update an auditDELETE /api/audits/{id}- Delete an auditPOST /api/audits/{id}/restore- Restore a soft-deleted audit
Searchable Fields: title, description, audit_type
Relations: manager, standard, auditItems
Special Parameters:
- with_details=true - Load all related audit items with full details
Audit Items
Base URL: /api/audit-items
GET /api/audit-items- List all audit itemsPOST /api/audit-items- Create a new audit itemGET /api/audit-items/{id}- Get a specific audit itemPUT /api/audit-items/{id}- Update an audit itemDELETE /api/audit-items/{id}- Delete an audit itemPOST /api/audit-items/{id}/restore- Restore a soft-deleted audit item
Searchable Fields: notes
Relations: audit, auditable, dataRequests
Programs
Base URL: /api/programs
GET /api/programs- List all programsPOST /api/programs- Create a new programGET /api/programs/{id}- Get a specific programPUT /api/programs/{id}- Update a programDELETE /api/programs/{id}- Delete a programPOST /api/programs/{id}/restore- Restore a soft-deleted program
Searchable Fields: name, description
Relations: programManager, standards, controls
Risks
Base URL: /api/risks
GET /api/risks- List all risksPOST /api/risks- Create a new riskGET /api/risks/{id}- Get a specific riskPUT /api/risks/{id}- Update a riskDELETE /api/risks/{id}- Delete a riskPOST /api/risks/{id}/restore- Restore a soft-deleted risk
Searchable Fields: title, description, mitigation
Relations: riskOwner, implementations
Vendors
Base URL: /api/vendors
GET /api/vendors- List all vendorsPOST /api/vendors- Create a new vendorGET /api/vendors/{id}- Get a specific vendorPUT /api/vendors/{id}- Update a vendorDELETE /api/vendors/{id}- Delete a vendorPOST /api/vendors/{id}/restore- Restore a soft-deleted vendor
Searchable Fields: name, description, contact_name, contact_email
Applications
Base URL: /api/applications
GET /api/applications- List all applicationsPOST /api/applications- Create a new applicationGET /api/applications/{id}- Get a specific applicationPUT /api/applications/{id}- Update an applicationDELETE /api/applications/{id}- Delete an applicationPOST /api/applications/{id}/restore- Restore a soft-deleted application
Searchable Fields: name, description, vendor.name
Relations: vendor, applicationOwner
Assets
Base URL: /api/assets
GET /api/assets- List all assetsPOST /api/assets- Create a new assetGET /api/assets/{id}- Get a specific assetPUT /api/assets/{id}- Update an assetDELETE /api/assets/{id}- Delete an assetPOST /api/assets/{id}/restore- Restore a soft-deleted asset
Searchable Fields: name, description, asset_tag
Relations: assetOwner, implementations
Data Requests
Base URL: /api/data-requests
GET /api/data-requests- List all data requestsPOST /api/data-requests- Create a new data requestGET /api/data-requests/{id}- Get a specific data requestPUT /api/data-requests/{id}- Update a data requestDELETE /api/data-requests/{id}- Delete a data request
Searchable Fields: request_text
Relations: audit, auditItem, responses
Data Request Responses
Base URL: /api/data-request-responses
GET /api/data-request-responses- List all data request responsesPOST /api/data-request-responses- Create a new data request responseGET /api/data-request-responses/{id}- Get a specific data request responsePUT /api/data-request-responses/{id}- Update a data request responseDELETE /api/data-request-responses/{id}- Delete a data request response
Searchable Fields: response_text
Relations: dataRequest, requestee
File Attachments
Base URL: /api/file-attachments
GET /api/file-attachments- List all file attachmentsPOST /api/file-attachments- Create a new file attachmentGET /api/file-attachments/{id}- Get a specific file attachmentPUT /api/file-attachments/{id}- Update a file attachmentDELETE /api/file-attachments/{id}- Delete a file attachment
Searchable Fields: filename, original_filename
Response Formats
Success Responses
Index (List) Response:
{
"current_page": 1,
"data": [...],
"first_page_url": "http://example.com/api/resources?page=1",
"from": 1,
"last_page": 5,
"last_page_url": "http://example.com/api/resources?page=5",
"next_page_url": "http://example.com/api/resources?page=2",
"path": "http://example.com/api/resources",
"per_page": 15,
"prev_page_url": null,
"to": 15,
"total": 75
}
Show/Create/Update Response:
{
"data": {
"id": 1,
"title": "Example Resource",
...
}
}
Delete Response:
- Status: 204 No Content
- Body: Empty
Error Responses
401 Unauthorized:
{
"message": "Unauthenticated."
}
403 Forbidden:
{
"message": "This action is unauthorized."
}
404 Not Found:
{
"message": "No query results for model..."
}
422 Validation Error:
{
"message": "The given data was invalid.",
"errors": {
"field_name": [
"The field name is required."
]
}
}
429 Rate Limit Exceeded:
{
"message": "Too Many Attempts."
}
Example Usage
Create a New User
curl -X POST "https://your-domain.com/api/users" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"name": "Alice Johnson",
"email": "[email protected]",
"password": "SecurePassword123!",
"password_confirmation": "SecurePassword123!",
"roles": ["Security Admin"]
}'
List Users with Roles
curl -X GET "https://your-domain.com/api/users?with=roles" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
List Controls with Search and Pagination
curl -X GET "https://your-domain.com/api/controls?search=encryption&per_page=10&page=1" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Create a New Standard
curl -X POST "https://your-domain.com/api/standards" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"code": "NIST-800-53",
"title": "NIST Special Publication 800-53",
"description": "Security and Privacy Controls",
"status": "active"
}'
Get Audit with Full Details
curl -X GET "https://your-domain.com/api/audits/1?with_details=true" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Update an Implementation
curl -X PUT "https://your-domain.com/api/implementations/5" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"status": "implemented",
"effectiveness": "effective"
}'
Delete a Risk
curl -X DELETE "https://your-domain.com/api/risks/3" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Restore a Deleted Control
curl -X POST "https://your-domain.com/api/controls/7/restore" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Security Best Practices
- Always use HTTPS in production
- Keep tokens secure - never commit them to version control
- Rotate tokens regularly - generate new tokens periodically
- Use appropriate permissions - follow the principle of least privilege
- Monitor API usage - watch for unusual patterns or rate limit hits
- Validate all input - the API performs server-side validation
- Handle errors gracefully - check response status codes
Support
For issues or questions about the API, please create an issue on the OpenGRC GitHub repository.