# Print STA Native Partner API v1 — AI/LLM Integration Contract Canonical human docs: https://native.print-sta.com.br/api/ Machine contract: https://native.print-sta.com.br/api/openapi-v1.yaml API base URL: https://api.print-sta.com.br/v1 Contract family: Print STA Native / Partner API v1 PURPOSE This file is optimized for LLMs, coding agents, RAG systems and autonomous integration tools. Treat MUST/MUST NOT rules as invariants. Do not infer undocumented API behavior. SOURCE-OF-TRUTH ORDER 1. Runtime GET /v1/managed/capabilities for feature availability. 2. Stable implementation in supabase/functions/print-sta-partner-api/index.ts. 3. /api/openapi-v1.yaml for routes, methods and request schemas. 4. /api/ human documentation for integration guidance. If these disagree, STOP automatic rollout. Do not guess. Prefer the runtime capability state for feature enablement and report the discrepancy. STABLE API SURFACE GET /managed/health GET /managed/capabilities POST /managed/enroll POST /accounts POST /accounts/{account_id}/deactivate POST /accounts/{account_id}/enrollments GET /accounts/{account_id}/devices POST /accounts/{account_id}/devices/{device_id}/deactivate GET /accounts/{account_id}/printers PATCH /accounts/{account_id}/printers/{printer_id} POST /accounts/{account_id}/jobs GET /accounts/{account_id}/jobs GET /accounts/{account_id}/jobs/{job_id} DO NOT INVENT THESE ROUTES POST /pairing/redeem is not part of the stable Partner API v1. GET /accounts/{account_id} is not part of the stable Partner API v1. POST /accounts/{account_id}/reactivate is not part of the stable Partner API v1. Printer test is not part of the stable Partner API v1. Do not generate code that calls them. WEBHOOK STATUS The dev branch contains Partner-scoped webhook infrastructure in separate functions, but stable /managed/capabilities currently reports features.webhooks=false. Therefore external production integration MUST NOT depend on webhooks until runtime capabilities returns webhooks=true and the stable docs/OpenAPI expose the public webhook contract. Until then, observe print completion by GET /accounts/{account_id}/jobs/{job_id} or paginated GET /accounts/{account_id}/jobs. AUTHORITY MODEL — CRITICAL Partner credentials are server-to-server secrets. Authorization format: Authorization: Bearer Partner credentials normally use pst_live_... or pst_test_... prefixes. The server derives Partner, Application, environment and effective scopes from the credential. Client/tenant input MUST NOT be allowed to choose or override partner, partner_id, provider, account_id or environment where the stable API rejects authority overrides. Operational requests MUST NOT append ?environment=... . account_id, device_id, printer_id and job_id are opaque Print STA public UUIDs. Never derive, encode business meaning into or synthesize them. SECRET HANDLING MUST keep Partner credential on trusted backend only. MUST NOT embed Partner credential in browser JavaScript, tenant frontend, Windows Agent, mobile app or logs. Enrollment tokens are single-use secrets and MUST be short-lived and delivered only to the intended Agent installation. Device credentials returned by /managed/enroll belong only to that Agent/device. Never log full Partner credentials, enrollment tokens, device credentials, print content containing sensitive data or webhook HMAC secrets. ENVIRONMENTS The current architecture is production-only for operational Partner flows. LIVE credentials are operational. TEST credentials are intended for diagnostics/capabilities under the current effective-scope policy. Do not build an operational TEST printing workflow unless /managed/capabilities and the issued credential explicitly make it available in a future contract revision. SCOPES diagnostics:read => GET /managed/health, GET /managed/capabilities accounts:write => POST /accounts, POST /accounts/{id}/deactivate devices:read => GET /accounts/{id}/devices devices:write => POST /accounts/{id}/enrollments, POST /accounts/{id}/devices/{device_id}/deactivate printers:read => GET /accounts/{id}/printers printers:write => PATCH /accounts/{id}/printers/{printer_id} jobs:read => GET /accounts/{id}/jobs, GET /accounts/{id}/jobs/{job_id} jobs:write => POST /accounts/{id}/jobs webhooks:write => present only for dev webhook preview surface; not proof that stable webhooks are enabled. A missing required scope produces HTTP 403 SCOPE_REQUIRED. REQUEST CONVENTIONS POST/PATCH stable routes require Content-Type: application/json. Maximum HTTP request body: 16,777,216 bytes. Maximum decoded print content: 10,485,760 bytes. Optional X-Correlation-Id: 8..128 chars from [A-Za-z0-9._:-]. Invalid input correlation IDs are not authoritative; server may replace them. Every stable Partner API response supplies request/correlation identifiers. RESPONSE ENVELOPE Typical success: { "code": "SOME_SUCCESS_CODE", "data": { ... }, "request_id": "req_...", "correlation_id": "cor_..." } Stable API error: { "code": "ERROR_CODE", "message": "Human-readable message", "retryable": false, "request_id": "req_...", "correlation_id": "cor_..." } AI MUST persist request_id and correlation_id in operational logs/telemetry, but MUST redact secrets. GOLDEN INTEGRATION FLOW A. Call GET /managed/health using the Partner credential. B. Call GET /managed/capabilities and gate feature use from the returned capabilities. C. POST /accounts using the ERP tenant stable external_id and human display_name. D. Store data.account_id as the opaque mapping for this tenant. E. POST /accounts/{account_id}/enrollments and securely pass data.enrollment_token to the Windows Agent installation. F. The Agent POSTs /managed/enroll with enrollment_token and a UUID installation_id. This call does not use the Partner Bearer credential. G. Once Agent/printer sync is established, GET /accounts/{account_id}/printers. H. Select only a printer that is logically enabled and operationally available. I. POST /accounts/{account_id}/jobs with a stable Idempotency-Key. J. Poll GET /accounts/{account_id}/jobs/{job_id} until printed or failed. K. Preserve IDs and trace identifiers for support/audit. ACCOUNT PROVISIONING POST /accounts Required body: { "external_id": "stable ERP tenant id, 1..160 chars", "display_name": "tenant display name, 2..120 chars" } The database contract is idempotent by Partner + external tenant id and reconciles an existing managed Account rather than requiring the caller to manufacture an Account ID. Expected success code: ACCOUNT_PROVISIONED. Known data fields include contract=print_sta_partner_account_v1, account_id, external_id, partner and status. Always store the returned account_id. Never construct it from external_id. ACCOUNT DEACTIVATION POST /accounts/{account_id}/deactivate Body may contain reason. If reason is omitted, the stable endpoint supplies a server default. Deactivation preserves history. Do not interpret deactivation as destructive deletion. ENROLLMENT CREATION POST /accounts/{account_id}/enrollments Body: {"ttl_seconds": 600} ttl_seconds defaults to 600 and must be integer 60..1800. Expected success HTTP 201 and code ENROLLMENT_CREATED. The enrollment_token is secret, single-use and time-limited. AGENT ENROLLMENT POST /managed/enroll NO Partner Bearer credential on this flow. Required: enrollment_token, installation_id (UUID). Optional server-bounded metadata: display_name <=120, hostname <=255, operating_system <=120, agent_version <=40. Server generates a device credential and returns it to the Agent. Current credential expiry is 180 days from enrollment. Do not reuse consumed enrollment tokens. DEVICES GET /accounts/{account_id}/devices Public availability values: online, offline, revoked. Do not reproduce the backend presence algorithm in the ERP; use returned status. List is cursor-paginated. Device items can include: device_id, friendly_code, display_name, hostname, operating_system, agent_version, status, raw_status, last_seen_at, printer_count, created_at. DEACTIVATE DEVICE POST /accounts/{account_id}/devices/{device_id}/deactivate Optional body reason. The database requires a valid 10..500 character reason; the HTTP endpoint provides a valid default if omitted. This revokes active device credentials/sessions. PRINTERS GET /accounts/{account_id}/printers List is cursor-paginated. Relevant fields include printer_id, device_id, system_name, alias, display_name, enabled, status, raw_status, device_status, is_default, last_seen_at and capabilities. Do not assume printer existence means it is printable. Before creating a job, prefer enabled=true and status=online. If the printer is offline or disabled, surface the condition to the ERP/operator instead of blind retry loops. PATCH PRINTER PATCH /accounts/{account_id}/printers/{printer_id} At least one of enabled:boolean or display_name:string must be present. Empty display_name restores the detected system name. Backend validates display name length up to 180 chars. CREATE JOB — IDEMPOTENCY IS MANDATORY POST /accounts/{account_id}/jobs Required header: Idempotency-Key Allowed key regex: ^[A-Za-z0-9._:-]{8,128}$ Required body fields: printer_id, content. Optional: external_id <=120, title <=160, copies 1..20 default 1, expires_at parseable datetime. Content: - text: type=text, encoding=utf8, data=plain UTF-8 string - raw: type=raw, encoding=base64, data=standard Base64 string - pdf: type=pdf, encoding=base64, data=standard Base64 string; decoded bytes must start with %PDF- Decoded content must contain at least 1 byte and at most 10 MiB. IDEMPOTENCY ALGORITHM FOR CLIENTS Choose one stable key per logical print intent, e.g. order::receipt:v1. On transport timeout or retryable server failure, resend the SAME logical payload with the SAME Idempotency-Key. Do not generate a new key merely because the first response was lost. First creation returns HTTP 201 code JOB_CREATED. Exact replay returns HTTP 200 code JOB_IDEMPOTENT_REPLAY. Same key reused for a different logical request returns HTTP 409 PRINT_STA_IDEMPOTENCY_CONFLICT. Do not retry an idempotency conflict automatically. JOB STATES Stable public states: queued, processing, printed, failed. printed and failed are terminal for normal client polling. Do not invent accepted, completed, cancelled or spooler-specific states as stable Partner API v1 states. raw_status may contain internal details; business logic should prefer the stable public status unless explicitly documented otherwise. LIST JOBS GET /accounts/{account_id}/jobs Optional status filter: queued|processing|printed|failed. Optional printer_id UUID filter. Default limit=50; allowed 1..100. Use next_cursor exactly as returned. GET JOB GET /accounts/{account_id}/jobs/{job_id} Use for authoritative status tracking after creation. PAGINATION Devices/printers default limit=100; jobs default limit=50. All list limits are 1..100. Response data has items, has_more, next_cursor. Cursor is opaque. MUST NOT decode, edit, infer or synthesize cursor values. Pass next_cursor verbatim. Do not replace cursor pagination with offset pagination. ERROR AND RETRY POLICY 400: fix request; no blind retry. 401: refresh/replace credential or enrollment token; no blind retry. 403: scope/authority problem; no blind retry. 404: wrong/missing resource; no blind retry. 409: state or idempotency conflict; inspect code; no blind retry. 413: reduce payload/content; no unchanged retry. 415: fix Content-Type; no unchanged retry. 429: retry with exponential backoff + jitter and bounded attempts. 500/503: retry only when response says retryable=true; use exponential backoff + jitter and bounded attempts. The response retryable boolean is the primary automatic-retry signal. Never create infinite retry loops. RATE LIMITS — CURRENT IMPLEMENTATION General authenticated Partner request: 900/min per Partner credential context. account.provision: 60/min. account.deactivate: 30/min. enrollment.create: 60/min. device.enroll: 20/min per enrollment-token subject. devices.list: 300/min. devices.deactivate: 60/min. printers.list: 300/min. printers.update: 120/min. jobs.create: 300/min. jobs.list: 300/min. jobs.detail: 600/min. These are protection ceilings, not throughput targets. OBSERVABILITY HEADERS ON STABLE PARTNER API X-Print-STA-Version X-Print-STA-API-Contract-Version X-Print-STA-Managed-Contract-Version X-Print-STA-Request-Id X-Print-STA-Correlation-Id Cache-Control: no-store Store trace IDs for support and distributed tracing. AUTONOMOUS-CODING SAFETY RULES MUST call capabilities before deciding optional feature support. MUST use least-privilege scopes. MUST keep Partner credential S2S only. MUST use returned opaque IDs. MUST implement Idempotency-Key for job creation. MUST handle printer unavailable state before sending. MUST handle printed/failed terminal states. MUST implement bounded backoff for retryable failures. MUST preserve trace IDs. MUST ignore unknown response fields for forward-compatible additive changes. MUST NOT infer undocumented routes or fields. MUST NOT use preview features in production automatically. MUST NOT allow tenant input to override Partner/environment authority. MUST NOT log secrets. MUST NOT retry validation/auth/idempotency conflicts blindly. MUST NOT decode cursor for business logic. IMPLEMENTATION READINESS CHECKLIST [ ] GET /managed/health succeeds. [ ] GET /managed/capabilities is parsed and feature-gated. [ ] Credential scopes are least-privilege. [ ] external_id -> account_id mapping is persisted. [ ] Repeated account provisioning is handled as reconciliation. [ ] Enrollment token is transferred securely and only once. [ ] Agent enrollment is separated from Partner S2S credentials. [ ] Printer selection rejects disabled/unavailable printers. [ ] Job creation always uses stable Idempotency-Key. [ ] Exact idempotent replay test passes. [ ] Idempotency conflict test is handled without duplicate printing. [ ] text/raw/pdf encoding is implemented only as required by the integration. [ ] 10 MiB decoded content limit is enforced client-side where practical. [ ] Cursor pagination is implemented verbatim. [ ] 429 and retryable 5xx use bounded exponential backoff + jitter. [ ] 4xx validation/auth errors do not trigger blind retry. [ ] request_id/correlation_id are retained in telemetry. [ ] Secrets and print payloads are redacted from logs. [ ] Webhooks remain disabled unless runtime capability is true and stable contract is published. FOR SDK GENERATORS Use openapi-v1.yaml as the route/schema source. Generated SDKs should expose a configurable base URL but default to https://api.print-sta.com.br/v1. Generated clients should support injecting X-Correlation-Id. Generated createJob should require Idempotency-Key at compile-time or method-call time. Do not generate methods for preview-excluded routes. FOR AI AGENTS MODIFYING AN EXISTING ERP First map the ERP's tenant identifier, print trigger, document rendering format, printer-selection UX, retry mechanism, audit/logging and lifecycle events. Then implement the Golden Integration Flow with minimal changes to the ERP. Do not refactor unrelated ERP modules solely to integrate Print STA Native. Preserve the ERP's existing print text/layout where the business requirement is only transport substitution. Keep any previous provider integration (for example a legacy print provider) isolated unless the migration explicitly authorizes its removal. END OF CONTRACT