API v1

FlexiMetaDoc API Reference

Versioned, deterministic reference for integrators, security reviewers, and auditors.

Use the onboarding section below as the primary first-read surface for new integrations.

Standard Error Object Schema (All 4xx/5xx Responses)

Field Requirement Type Notes
error.code Required string Machine-readable stable error code (for example: VALIDATION_FAILED).
error.message Required string Human-readable deterministic message.
error.details Optional array Defaults to empty array when omitted.
error.correlationId Required UUID Echoes X-Correlation-Id for audit traceability.
error.timestampUtc Required ISO-8601 UTC string Server time when error was produced.
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "One or more request fields are invalid.",
    "details": [
      {
        "field": "title",
        "issue": "Title is required"
      }
    ],
    "correlationId": "9f05af26-073d-4c0d-a860-34beea5428f0",
    "timestampUtc": "2026-04-09T00:00:00Z"
  }
}

Authentication

Field Requirement Details
Authorization Required Use Bearer <jwt_token>.
Token algorithm Required JWT with RS256 signature; include sub, scope, iat, and exp.
Expiry behavior Required Expired/invalid token returns 401 with standard error object schema.
Insufficient scope Required Insufficient scope returns 403 with standard error object schema.
{
  "error": {
    "code": "AUTH_TOKEN_EXPIRED",
    "message": "The access token is expired.",
    "details": [
      {
        "field": "Authorization",
        "issue": "Expired token"
      }
    ],
    "correlationId": "9f05af26-073d-4c0d-a860-34beea5428f0",
    "timestampUtc": "2026-04-09T00:00:00Z"
  }
}

Incoming API onboarding

Deterministic onboarding workflow for inbound API consumers with explicit contract fields, payload examples, and failure handling semantics.

Changelog

Last updated: 2026-04-09 (UTC)
  • v1.0.1 - Clarified schemas, endpoint contracts, and webhook security controls.
  • v1.0.0 - Initial API v1 reference publication.

Register service identity

Provision a traceable service principal before any credential issuance.

Provisioning API field (POST /integrations/services) UI action field Requirement Deterministic rule
tenantId Tenant Required UUID; must match the operator tenant context.
serviceName Service name Required 3-100 chars; unique per tenant.
environment Environment Required Enum: dev, test, prod.
description Description Optional 0-500 chars; defaults to empty string when omitted.
contactEmail Owner email Optional RFC 5322 format; used for lifecycle notifications.

Minimal payload

{
  "tenantId": "7f86bb03-e745-4f95-90b7-0f4f7abff25c",
  "serviceName": "erp-sync",
  "environment": "prod"
}

Maximal payload

{
  "tenantId": "7f86bb03-e745-4f95-90b7-0f4f7abff25c",
  "serviceName": "erp-sync",
  "environment": "prod",
  "description": "Inbound sync from ERP to FlexiMetaDoc",
  "contactEmail": "owner@example.com"
}

Issue inbound API credentials

Generate scoped credentials bound to a registered service identity.

Provisioning API field (POST /integrations/services/{serviceId}/keys) UI action field Requirement Deterministic rule
displayName Key label Required 1-100 chars; immutable for audit traceability.
scopes Scopes Required Non-empty string array; least-privilege only.
expiresAtUtc Expiration Required ISO-8601 UTC timestamp; must be within 365 days.
ipAllowList Allowed IPs Optional CIDR array; empty means any source IP.
metadata Metadata tags Optional String map for governance and change-control references.

Minimal payload

{
  "displayName": "erp-sync-primary",
  "scopes": ["documents.write"],
  "expiresAtUtc": "2026-10-01T00:00:00Z"
}

Maximal payload

{
  "displayName": "erp-sync-primary",
  "scopes": ["documents.write", "records.write", "records.read"],
  "expiresAtUtc": "2026-10-01T00:00:00Z",
  "ipAllowList": ["198.51.100.0/24", "203.0.113.10/32"],
  "metadata": {
    "ownerTeam": "finance-platform",
    "changeTicket": "CAB-2045"
  }
}

Sign request (X-Integration-Key, timestamp, nonce, signature)

Inbound API calls are accepted only when all signing headers validate within the replay window.

Header Requirement Validation rule
X-Integration-Key Required Matches an active key ID in the caller tenant scope.
X-Integration-Timestamp Required UTC epoch seconds; max clock skew ±300 seconds.
X-Integration-Nonce Required UUIDv4; single-use within a 10-minute replay cache.
X-Integration-Signature Required UPPERCASE_HEX(HMAC-SHA256(canonicalRequestUtf8Bytes, keySecretUtf8Bytes)). Lowercase hex and Base64 are invalid for v1.0.
canonicalRequest =
  HTTP_METHOD + "\n" +
  REQUEST_PATH + "\n" +
  UPPERCASE_HEX(SHA256(RAW_REQUEST_BODY_BYTES)) + "\n" +
  X-Integration-Timestamp + "\n" +
  X-Integration-Nonce

X-Integration-Signature = UPPERCASE_HEX(HMAC_SHA256(canonicalRequest, keySecret))

C# signing example (.NET)

using System.Security.Cryptography;
using System.Text;

static string SignRequest(
    string httpMethod,
    string requestPath,
    byte[] rawBodyBytes,
    string timestamp,
    string nonce,
    string keySecret)
{
    var bodyHash = SHA256.HashData(rawBodyBytes);
    var bodyHashHex = Convert.ToHexString(bodyHash); // uppercase hex

    var canonicalRequest =
        httpMethod + "\n" +
        requestPath + "\n" +
        bodyHashHex + "\n" +
        timestamp + "\n" +
        nonce;

    var canonicalBytes = Encoding.UTF8.GetBytes(canonicalRequest);
    var secretBytes = Encoding.UTF8.GetBytes(keySecret);
    var signature = HMACSHA256.HashData(secretBytes, canonicalBytes);

    return Convert.ToHexString(signature); // X-Integration-Signature
}

Deterministic auth diagnostics: malformed signature encoding returns failureCode=signature_invalid_encoding; valid uppercase hex with non-matching digest returns failureCode=signature_mismatch.

Rotate and revoke keys

Provisioning action API request UI action Required vs optional fields Deterministic result
Rotate key POST /integrations/services/{serviceId}/keys/{keyId}/rotate Generate replacement key reason Required, effectiveAtUtc Optional Existing key enters grace state until cutover; new key is immediately available.
Revoke key POST /integrations/services/{serviceId}/keys/{keyId}/revoke Revoke key reason Required, ticketRef Optional Key status changes to revoked and cannot be reactivated.

Minimal rotate payload

{
  "reason": "scheduled-rotation"
}

Maximal rotate payload

{
  "reason": "scheduled-rotation",
  "effectiveAtUtc": "2026-07-01T00:00:00Z"
}

Minimal revoke payload

{
  "reason": "suspected-compromise"
}

Maximal revoke payload

{
  "reason": "suspected-compromise",
  "ticketRef": "SEC-9081"
}

Failure-mode playbook (deterministic error objects)

All failures below use the same object shape for traceability: error.code, error.message, error.details[], error.correlationId, error.timestampUtc.

Expired key (401)

{
  "error": {
    "code": "INTEGRATION_KEY_EXPIRED",
    "message": "Integration key is expired.",
    "details": [{ "field": "X-Integration-Key", "issue": "Expired at 2026-10-01T00:00:00Z" }],
    "correlationId": "73ef112f-86bc-48fa-ae95-c7f5f3b7b6c1",
    "timestampUtc": "2026-10-01T00:02:10Z"
  }
}

Revoked key (401)

{
  "error": {
    "code": "INTEGRATION_KEY_REVOKED",
    "message": "Integration key has been revoked.",
    "details": [{ "field": "X-Integration-Key", "issue": "Revoked by admin policy" }],
    "correlationId": "f917ec57-9723-49c4-8388-37ef9fafe4f2",
    "timestampUtc": "2026-10-01T00:03:50Z"
  }
}

Signature mismatch (401)

{
  "error": {
    "code": "INTEGRATION_SIGNATURE_MISMATCH",
    "message": "Request signature validation failed.",
    "details": [{ "field": "X-Integration-Signature", "issue": "Computed signature does not match" }],
    "correlationId": "e72f6ff5-f6cc-4600-a5e1-502498d67230",
    "timestampUtc": "2026-10-01T00:04:12Z"
  }
}

Tenant-scope violation (403)

{
  "error": {
    "code": "INTEGRATION_TENANT_SCOPE_VIOLATION",
    "message": "Integration key is not authorized for the target tenant.",
    "details": [{ "field": "tenantId", "issue": "Requested tenant does not match key scope" }],
    "correlationId": "3526814f-c56f-40dd-8f95-7c5dc82f982a",
    "timestampUtc": "2026-10-01T00:05:03Z"
  }
}

Conventions

Convention Requirement Definition
Base URL Required https://api.fleximetadoc.example/v1
Content-Type Required application/json; charset=utf-8.
Idempotency-Key Required for POST/PATCH writes UUID, retained for 24 hours; duplicate keys return original outcome.
Pagination query params Optional page default 1; pageSize default 25, max 100.
Rate limits Required 120 requests/minute per token. 429 returns Retry-After seconds.
X-Correlation-Id Required Client-supplied UUID, echoed in responses for end-to-end tracing.

Endpoint Catalog

Endpoint Group: Documents

POST /documents - Create a document resource.

Field Type Requirement Behavior
title string Required 1-200 chars.
ownerId UUID Required Must reference an existing owner.
description string? Optional Nullable. Defaults to null when omitted.
tags string[] Optional Defaults to [] when omitted.
retentionDays int? Optional Nullable. Defaults to tenant policy when omitted.

Minimal required payload

{
  "title": "Q2 Compliance Summary",
  "ownerId": "64f7f01a-cf17-4ec0-af30-79d8aadcce5f"
}

Maximal payload

{
  "title": "Q2 Compliance Summary",
  "ownerId": "64f7f01a-cf17-4ec0-af30-79d8aadcce5f",
  "description": "Regulatory and audit report",
  "tags": ["audit", "finance", "q2"],
  "retentionDays": 365
}

Endpoint Group: Records

POST /records - Create an indexed record within a document.

Field Type Requirement Behavior
documentId UUID Required Must reference an existing document.
recordType enum Required Allowed values: invoice, note, event.
effectiveDateUtc datetime Required ISO-8601 UTC.
metadata object Optional Defaults to {} when omitted.
externalReference string? Optional Nullable. Defaults to null when omitted.

Minimal required payload

{
  "documentId": "4f6f517f-c0dc-43a9-b250-62e301983dc4",
  "recordType": "note",
  "effectiveDateUtc": "2026-04-09T00:00:00Z"
}

Maximal payload

{
  "documentId": "4f6f517f-c0dc-43a9-b250-62e301983dc4",
  "recordType": "invoice",
  "effectiveDateUtc": "2026-04-09T00:00:00Z",
  "metadata": {
    "currency": "USD",
    "amount": "1250.00",
    "approvedBy": "ops-team"
  },
  "externalReference": "ERP-PO-11883"
}

Request/Response Examples

Success path (201 Created)

{
  "data": {
    "id": "de65db84-f852-44c2-9499-0f778530f2ef",
    "status": "created",
    "createdAtUtc": "2026-04-09T00:00:00Z"
  },
  "meta": {
    "apiVersion": "v1",
    "correlationId": "9f05af26-073d-4c0d-a860-34beea5428f0"
  }
}

Failure path (400 Bad Request)

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "One or more request fields are invalid.",
    "details": [
      {
        "field": "recordType",
        "issue": "Value must be one of: invoice, note, event"
      }
    ],
    "correlationId": "9f05af26-073d-4c0d-a860-34beea5428f0",
    "timestampUtc": "2026-04-09T00:00:00Z"
  }
}

Webhooks

  • Delivery: HTTPS POST with JSON body.
  • Signature header: X-FMD-Signature format sha256=<hex_digest>.
  • Timestamp header: X-FMD-Timestamp UNIX seconds.
  • Replay protection: Reject payloads older than 300 seconds and deduplicate event IDs for 24 hours.
  • Retry behavior: Non-2xx responses trigger retries with exponential backoff.

Signature verification pseudocode

signedPayload = X-FMD-Timestamp + "." + rawBody
expected = HMAC_SHA256(webhookSecret, signedPayload)
if !constantTimeEquals(expected, X-FMD-Signature): reject(401)
if abs(currentUnixSeconds - X-FMD-Timestamp) > 300: reject(401)
if eventIdAlreadyProcessed: reject(409)
acknowledgeWith2xx()

Security Expectations

  • Credential handling: Keep credentials in a managed secret store; never commit or log secrets.
  • Least privilege scopes: Request only required scopes and rotate tokens on a defined schedule.
  • Retry and backoff: Use exponential backoff with jitter for 429/5xx; cap at 5 retry attempts.
  • Input validation: Validate UUIDs, enum values, timestamps, and string lengths before request submission.
  • Deterministic failures: Handle non-success responses through the standard error schema and preserve correlation IDs.