# Create an API key
Source: https://developers.factify.com/api-reference/apikeys/create-an-api-key
/openapi.json post /v1/api-keys
Creates a new API key for the caller's organization. The full
secret is returned exactly once in the response and cannot be
retrieved later — store it securely on receipt.
Keys cannot be updated; rotate by creating a new key and
revoking the old one.
Authorization: requires organization admin role.
# List API keys
Source: https://developers.factify.com/api-reference/apikeys/list-api-keys
/openapi.json get /v1/api-keys
Lists API keys for the caller's organization. Secrets are
never returned — use the `prefix` field to identify a key in
the UI.
Authorization: requires organization admin role.
# Revoke an API key
Source: https://developers.factify.com/api-reference/apikeys/revoke-an-api-key
/openapi.json delete /v1/api-keys/{api_key_id}
Revokes an API key, immediately preventing it from being used
for authentication. Revocation is permanent — to restore
access, create a new key.
Authorization: requires organization admin role.
# Accept an invitation
Source: https://developers.factify.com/api-reference/invitations/accept-an-invitation
/openapi.json post /v1/organization/invitations/{invitation_id}/accept
Accepts a pending invitation and adds the authenticated user
as a member of the organization with the invited role.
Returns 404 if the invitation does not exist and 422 if it
has expired.
# Invite a member by email
Source: https://developers.factify.com/api-reference/invitations/invite-a-member-by-email
/openapi.json post /v1/organization/invitations
Creates an invitation for the given email and role.
Invitations expire 7 days after creation.
Authorization: requires `organization#manage` (owner or admin).
# List pending invitations
Source: https://developers.factify.com/api-reference/invitations/list-pending-invitations
/openapi.json get /v1/organization/invitations
Lists pending invitations for the caller's current
organization.
Authorization: requires `organization#manage` (owner or admin).
# Resend an invitation email
Source: https://developers.factify.com/api-reference/invitations/resend-an-invitation-email
/openapi.json post /v1/organization/invitations/{invitation_id}/resend
Resends the invitation email to the recipient. Useful when the
original email was lost or close to expiring. Only pending,
non-expired invitations can be resent.
Authorization: requires `organization#manage` (owner or admin).
# Revoke an invitation
Source: https://developers.factify.com/api-reference/invitations/revoke-an-invitation
/openapi.json delete /v1/organization/invitations/{invitation_id}
Revokes a pending invitation. Any link previously sent to the
recipient becomes invalid.
Authorization: requires `organization#manage` (owner or admin).
# List organization members
Source: https://developers.factify.com/api-reference/members/list-organization-members
/openapi.json get /v1/organization/members
Lists members of the caller's current organization.
Authorization: requires `organization#list_members`, which the
SpiceDB schema grants to any organization member (owner, admin,
or regular member).
# Remove a member
Source: https://developers.factify.com/api-reference/members/remove-a-member
/openapi.json delete /v1/organization/members/{user_id}
Removes a member from the organization. Returns 422 if the
user is the last remaining owner.
Authorization: requires `organization#manage` (owner or admin).
# Update a member's role
Source: https://developers.factify.com/api-reference/members/update-a-members-role
/openapi.json patch /v1/organization/members/{user_id}
Updates a member's role within the organization. Returns 422
if the change would demote the last remaining owner.
Authorization: requires `organization#manage` (owner or admin).
# Create an organization
Source: https://developers.factify.com/api-reference/organizations/create-an-organization
/openapi.json post /v1/organization
Creates a new organization with the authenticated user as the
first owner.
Service-account callers cannot create organizations; the call
returns 403.
# Get the current organization
Source: https://developers.factify.com/api-reference/organizations/get-the-current-organization
/openapi.json get /v1/organization
Returns the organization the caller's token is scoped to —
the owning organization for API-key callers, the selected
organization for user-session callers.
# List organizations
Source: https://developers.factify.com/api-reference/organizations/list-organizations
/openapi.json get /v1/organizations
Lists organizations the authenticated user belongs to (as
owner, admin, or member).
Requires a user-bearing auth method (session, JWT, or OAuth);
API-key / service-account callers receive 403.
# Update the organization
Source: https://developers.factify.com/api-reference/organizations/update-the-organization
/openapi.json patch /v1/organization
Updates the caller's current organization. Only the name is
mutable via this endpoint.
Authorization: requires `organization#update` (owner only).
# Get plan
Source: https://developers.factify.com/api-reference/plans/get-plan
/openapi.json get /v1/plans/{planId}
Returns the plan with inline claim_slots and submissions. body_md_resolved is populated only after the plan is locked.
# List plans
Source: https://developers.factify.com/api-reference/plans/list-plans
/openapi.json get /v1/plans
# Lock plan
Source: https://developers.factify.com/api-reference/plans/lock-plan
/openapi.json post /v1/plans/{planId}/lock
Locks the plan, computing and storing body_md_resolved from bound claims.
Pure-render path — does NOT invoke any workflow body. Execution lives
separately at POST /v1/plans/{planId}/run (Runtime layer) and
requires a prior /lock; the plan + bound claims are immutable after lock.
Returns 409 when the plan cannot be locked. The `floating_rubrics` field
is present only when the conflict is caused by plan-scoped rubric slots
that CLW Pass A matching has not yet bound; other conflict reasons (already locked,
submission still processing) omit it.
# Open plan
Source: https://developers.factify.com/api-reference/plans/open-plan
/openapi.json post /v1/plans
Instantiate a new plan from a workflow.
# Get document quota and usage
Source: https://developers.factify.com/api-reference/usage/get-document-quota-and-usage
/openapi.json get /v1/quota
Returns the document quota for the caller's organisation:
the limit, the current document count, the remaining
balance, and the next reset timestamp.
# Get usage and quota for the caller's active organisation
Source: https://developers.factify.com/api-reference/usage/get-usage-and-quota-for-the-callers-active-organisation
/openapi.json get /v1/me/quota
Returns current usage and quota for the authenticated user's
currently-active organisation. Requires a user-bearing auth
method (session/JWT/OAuth); API-key callers — which carry no
user identity — receive 403.
# Get current user
Source: https://developers.factify.com/api-reference/users/get-current-user
/openapi.json get /v1/me
Returns the authenticated user's profile.
Only available to user accounts (Cognito session, OAuth, or
dev JWT). API-key callers have no user identity and receive
403.
# Update current user profile
Source: https://developers.factify.com/api-reference/users/update-current-user-profile
/openapi.json patch /v1/me
Updates the authenticated user's profile. Uses RFC 7396
(JSON Merge Patch) semantics: omitted fields are left
unchanged. `display_name` is required on every request and
cannot be cleared.
`given_name` and `family_name` accept `null` to clear. Empty
string is rejected with 422 — use `null`.
Email cannot be updated through this endpoint.
# Create workflow
Source: https://developers.factify.com/api-reference/workflows/create-workflow
/openapi.json post /v1/workflows
# Get workflow
Source: https://developers.factify.com/api-reference/workflows/get-workflow
/openapi.json get /v1/workflows/{workflowId}
Returns the active revision if one exists, otherwise the draft.
# List workflows
Source: https://developers.factify.com/api-reference/workflows/list-workflows
/openapi.json get /v1/workflows
# Trash workflow
Source: https://developers.factify.com/api-reference/workflows/trash-workflow
/openapi.json delete /v1/workflows/{workflowId}
Soft-deletes the workflow so it no longer appears in active workflow lists. This is exposed in the app as "Trash process"; restore and include-trashed listing are not available yet.
# Invite Organization Member
Source: https://developers.factify.com/examples/invite-member
Send invitations to add members to your organization.
## Overview
Invitations allow you to add members to your organization. When you create an invitation, the recipient receives an email with a link to accept. Invitations expire after 7 days.
## Prerequisites
* An organization ID (find yours in the [Developer Dashboard](https://platform.factify.com))
* A valid API key with permission to manage organization members
## Code Example
```typescript TypeScript theme={null}
import { Factify } from "@factify/sdk";
const factify = new Factify({ bearerAuth: process.env.FACTIFY_KEY });
async function inviteMember(organizationId: string, email: string) {
const result = await factify.organizations.invites.create({
organizationId,
body: {
email,
message: "Welcome to the team!" // Optional custom message
}
});
console.log(`Invitation sent: ${result.invite?.id}`);
return result.invite;
}
inviteMember(
"org_01h2xcejqtf2nbrexx3vqjhp41",
"pam.beesly@dundermifflin.com"
);
```
```python Python theme={null}
import os
from factify import Factify
factify = Factify(bearer_auth=os.environ["FACTIFY_KEY"])
def invite_member(organization_id: str, email: str):
response = factify.organizations.invites.create(
organization_id=organization_id,
email=email,
message="Welcome to the team!" # Optional custom message
)
print(f"Invitation sent: {response.result.invite.id}")
return response.result.invite
invite_member(
"org_01h2xcejqtf2nbrexx3vqjhp41",
"pam.beesly@dundermifflin.com"
)
```
## Response
```json theme={null}
{
"invite": {
"id": "inv_01h2xcejqtf2nbrexx3vqjhp42",
"organization_id": "org_01h2xcejqtf2nbrexx3vqjhp41",
"email": "pam.beesly@dundermifflin.com",
"status": "ORGANIZATION_INVITE_STATUS_PENDING",
"sender": {
"id": "user_01h2xcejqtf2nbrexx3vqjhp40",
"type": "USER_TYPE_USER_ACCOUNT",
"name": "John Doe"
},
"created_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-22T09:30:00Z",
"message": "Welcome to the team!"
}
}
```
## Options
| Parameter | Type | Description |
| ---------------- | ------ | ---------------------------------------------- |
| `organizationId` | string | Required. The organization to invite to |
| `email` | string | Required. Email address of the recipient |
| `message` | string | Optional. Custom message (max 2000 bytes) |
| `idempotencyKey` | string | Optional. Client-provided key for safe retries |
## Idempotency
If you include an `idempotency_key`, duplicate requests within 24 hours return the original response without resending the email. This is useful for retry logic.
```typescript TypeScript theme={null}
const result = await factify.organizations.invites.create({
organizationId: "org_01h2xcejqtf2nbrexx3vqjhp41",
body: {
email: "pam.beesly@dundermifflin.com",
idempotencyKey: "my-unique-request-id-123"
}
});
```
```python Python theme={null}
response = factify.organizations.invites.create(
organization_id="org_01h2xcejqtf2nbrexx3vqjhp41",
email="pam.beesly@dundermifflin.com",
idempotency_key="my-unique-request-id-123"
)
```
## Listing Invitations
Check pending invitations for your organization:
```typescript TypeScript theme={null}
const invites = await factify.organizations.invites.list({
organizationId: "org_01h2xcejqtf2nbrexx3vqjhp41",
status: ["ORGANIZATION_INVITE_STATUS_PENDING"]
});
for await (const page of invites) {
console.log(page.items);
}
```
```python Python theme={null}
invites = factify.organizations.invites.list(
organization_id="org_01h2xcejqtf2nbrexx3vqjhp41",
status=["ORGANIZATION_INVITE_STATUS_PENDING"]
)
for page in invites:
print(page.result.items)
```
## Revoking an Invitation
Cancel a pending invitation:
```typescript TypeScript theme={null}
await factify.organizations.invites.revoke({
organizationId: "org_01h2xcejqtf2nbrexx3vqjhp41",
inviteId: "inv_01h2xcejqtf2nbrexx3vqjhp42"
});
```
```python Python theme={null}
factify.organizations.invites.revoke(
organization_id="org_01h2xcejqtf2nbrexx3vqjhp41",
invite_id="inv_01h2xcejqtf2nbrexx3vqjhp42"
)
```
## Error Handling
| Error | Cause | Solution |
| --------------------- | -------------------------------- | --------------------------------------------------- |
| `FAILED_PRECONDITION` | Email belongs to existing member | User is already in the organization |
| `PERMISSION_DENIED` | Insufficient permissions | Ensure your account can manage organization members |
| `NOT_FOUND` | Invalid organization ID | Verify the organization exists |
## Next Steps
Learn about API key management
Manage organization settings
# Authentication
Source: https://developers.factify.com/guides/authentication
Learn how to authenticate with the Factify API using API keys and Bearer tokens.
## Overview
All Factify API requests require authentication via Bearer tokens. This guide explains how to obtain and use your API credentials.
## Getting Your API Key
1. Log in to the [Developer Dashboard](https://platform.factify.com)
2. Navigate to **Manage** > **API Keys**
3. Click **Create API Key**
4. Copy your key immediately - it won't be shown again
Keep your API key secure. Never commit it to version control or expose it in client-side code.
## Using Your API Key
Include your API key in the `Authorization` header of every request:
```bash theme={null}
Authorization: Bearer
```
### SDK Configuration
The SDKs handle authentication automatically once configured:
```typescript TypeScript theme={null}
import { Factify } from "@factify/sdk";
const factify = new Factify({
bearerAuth: process.env.FACTIFY_KEY
});
```
```python Python theme={null}
from factify import Factify
import os
client = Factify(bearer_auth=os.environ["FACTIFY_KEY"])
```
```go Go theme={null}
import "github.com/factify-inc/factify-go"
client := factify.New(
factify.WithBearerAuth(os.Getenv("FACTIFY_KEY")),
)
```
## Environment Variables
We recommend storing your API key in environment variables:
```bash .env theme={null}
FACTIFY_KEY=ffy_live_xxxxxxxxxxxxxxxxxxxx
```
Use a `.env` file with a tool like `dotenv`:
```bash theme={null}
# .env.local
FACTIFY_KEY=ffy_test_xxxxxxxxxxxxxxxxxxxx
```
Set environment variables in your hosting platform:
* **Vercel**: Project Settings > Environment Variables
* **AWS**: Lambda configuration or Secrets Manager
* **Heroku**: Config Vars in Settings
## API Key Format
Factify API keys follow a structured format that includes environment indicators and embedded identifiers for efficient lookup:
```text theme={null}
ffy_{env}_{base32_uuid7}{base62_random}
Example: ffy_live_01j5q3k8m2n4p6r8t0v2x4z6y8abcdefghijklmnopqrstuvwxyz0123456789a
```
### Key Components
| Component | Description |
| ------------- | -------------------------------------------------------------------- |
| `ffy` | Factify identifier (enables security scanners to detect leaked keys) |
| `live`/`test` | Environment indicator |
| UUID7 | Time-sortable identifier for O(1) database lookup |
| Random | 256-bit entropy secret |
### Environment Types
| Type | Prefix | Environment | Capabilities |
| ---- | ----------- | ----------- | ----------------------------- |
| Test | `ffy_test_` | Sandbox | Full API access, no real data |
| Live | `ffy_live_` | Production | Full API access, real data |
Environment in the key **must** match the server's runtime environment. Using a `ffy_test_` key against production will return an `invalid_api_key` error.
## Key Rotation
To rotate your API key:
1. Generate a new key in the [Developer Dashboard](https://platform.factify.com)
2. Update your application with the new key
3. Verify the new key works
4. Revoke the old key
You can have up to 5 active API keys at once, allowing for zero-downtime rotation. [Manage API Keys →](https://platform.factify.com)
## Authentication Errors
| Status | Error | Solution |
| ------ | -------------------------- | ----------------------------------------------------------------------------- |
| `401` | `invalid_api_key` | Check your API key is correct |
| `401` | `expired_api_key` | Generate a new key in the [Developer Dashboard](https://platform.factify.com) |
| `403` | `insufficient_permissions` | Contact support to upgrade your plan |
```json Example Error Response theme={null}
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The API key provided is invalid or has been revoked"
}
}
```
# Error Handling
Source: https://developers.factify.com/guides/error-handling
Handle API errors gracefully with structured error responses.
## Overview
Factify uses conventional HTTP status codes and returns structured error responses.
## Error Response Format
All errors follow a consistent JSON structure:
```json theme={null}
{
"error": {
"type": "invalid_request_error",
"message": "Name cannot be empty",
"param": "name",
"code": "missing_required_field"
}
}
```
| Field | Type | Description |
| --------- | -------------- | ---------------------------------------- |
| `type` | string | Error category for broad handling |
| `code` | string | Specific error for programmatic handling |
| `message` | string | Human-readable explanation |
| `param` | string \| null | Field that caused the error |
## Error Types
| Type | HTTP Status | When |
| ----------------------- | ----------- | ------------------------------------ |
| `invalid_request_error` | 400 | Validation failed, malformed request |
| `authentication_error` | 401 | Missing or invalid API key |
| `authorization_error` | 403 | Valid key, insufficient permissions |
| `not_found_error` | 404 | Resource doesn't exist |
| `rate_limit_error` | 429 | Too many requests |
| `api_error` | 500+ | Server-side failure |
## SDK Error Classes
[`FactifyError`](https://github.com/factify-inc/factify-typescript/blob/main/src/models/errors/factifyerror.ts) is the base class for all HTTP error responses:
| Property | Type | Description |
| ------------------------- | ---------- | -------------------------- |
| `error.message` | `string` | Error message |
| `error.httpMeta.response` | `Response` | HTTP response with headers |
| `error.httpMeta.request` | `Request` | HTTP request details |
| `error.data$` | varies | Structured error data |
## Handling Errors
```typescript theme={null}
import { Factify } from "@factify/sdk";
import * as errors from "@factify/sdk/models/errors";
const factify = new Factify({
bearerAuth: process.env.FACTIFY_KEY,
});
async function run() {
try {
const result = await factify.apiKeys.list();
console.log(result);
} catch (error) {
// The base class for HTTP error responses
if (error instanceof errors.FactifyError) {
console.log(error.message);
console.log(error.httpMeta.response.status);
console.log(error.httpMeta.response.headers);
console.log(error.httpMeta.request);
// Handle specific error types
if (error instanceof errors.ErrorT) {
console.log(error.data$.error);
}
}
}
}
run();
```
## Network Errors
The SDK provides specific error classes for network issues:
| Error Class | Description |
| ------------------------- | -------------------------------------- |
| `ConnectionError` | Unable to connect to server |
| `RequestTimeoutError` | Request timed out |
| `RequestAbortedError` | Request was aborted |
| `InvalidRequestError` | Invalid request input |
| `ResponseValidationError` | Response doesn't match expected schema |
## Error Codes Reference
| Code | Description |
| ------------------------ | ---------------------------- |
| `missing_required_field` | Required field not provided |
| `invalid_field_value` | Field value fails validation |
| `invalid_enum_value` | Value not in allowed set |
| `invalid_file_type` | Uploaded file not PDF |
| `file_too_large` | File exceeds size limit |
| `invalid_page_token` | Pagination token invalid |
| Code | Description |
| ----------------- | ----------------------------- |
| `missing_api_key` | No Authorization header |
| `invalid_api_key` | Key format invalid or revoked |
| `expired_api_key` | Key has expired |
| Code | Description |
| -------------------------- | ------------------------ |
| `insufficient_permissions` | Key lacks required scope |
| Code | Description |
| --------------------- | ------------------------- |
| `resource_not_found` | Resource ID doesn't exist |
| `rate_limit_exceeded` | Request quota exhausted |
| `internal_error` | Unexpected server error |
# Rate Limiting
Source: https://developers.factify.com/guides/rate-limiting
Understand API rate limits and how the SDK handles them automatically.
## Overview
The API enforces rate limits to ensure stability for all users.
## Limits
| Endpoint Type | Limit |
| ----------------------- | ------------------------- |
| Read operations (GET) | 1,000 requests per minute |
| Write operations (POST) | 100 requests per minute |
## Rate Limit Headers
Every response includes rate limit information:
```http theme={null}
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1705312800
```
## Handling Rate Limits
When you exceed the limit, you'll receive a `429 Too Many Requests` response:
```json theme={null}
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after 32 seconds.",
"retry_after": 32
}
}
```
## Automatic Retries
The SDK automatically handles rate limiting with built-in retries and exponential backoff. You can customize this behavior:
```typescript theme={null}
const factify = new Factify({
bearerAuth: process.env.FACTIFY_KEY,
retryConfig: {
strategy: "backoff",
backoff: {
initialInterval: 1000,
maxInterval: 30000,
exponent: 1.5,
maxElapsedTime: 60000,
},
retryConnectionErrors: false,
},
});
```
You can also monitor your quota usage in the [Developer Dashboard](https://platform.factify.com).
## Best Practices
1. **Use pagination** - Fetch data in smaller batches rather than requesting everything at once
2. **Cache responses** - Store frequently accessed data locally to reduce API calls
3. **Monitor headers** - Track `X-RateLimit-Remaining` to avoid hitting limits
4. **Implement backoff** - The SDK handles this automatically, but be aware of retry behavior
# Factify Developer Portal
Source: https://developers.factify.com/introduction
APIs for organization management, workflow orchestration, usage controls, and agent-backed extraction.
# Factify API
Use the Factify API to manage organizations, API keys, workflow plans, usage controls, and extraction workflows.
```typescript theme={null}
import { Factify } from "@factify/sdk";
const factify = new Factify({ bearerAuth: process.env.FACTIFY_KEY });
const me = await factify.users.getCurrent();
console.log(me);
```
Configure API keys and request authentication.
Browse current REST endpoints.