# 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.