openapi: 3.0.3 info: title: Hatima Berega API (חתימה ברגע) version: "1.2" description: | REST API v1. אימות ב-Bearer API Key (psk_…) או OAuth2 access token (oat_…, ראו /oauth/token). מפתחות/לקוחות Sandbox יוצרים מעטפות מסומנות שאינן נספרות במכסה (כותרת X-PrivateSign-Sandbox). Bearer API Key (Scopes: envelopes:read, envelopes:write, evidence:read, contacts:write). כל POST תומך ב-Idempotency-Key (מפתח חוזר עם אותו payload מחזיר את אותה תגובה + Idempotent-Replayed: true; payload שונה → 409). כל תגובה נושאת X-Correlation-Id. Rate limit: 120 בקשות/דקה לארגון (429). Webhooks: POST JSON עם כותרות X-PrivateSign-Event, X-PrivateSign-Event-Id, X-PrivateSign-Timestamp, X-PrivateSign-Signature: sha256=HMAC_SHA256(secret, timestamp + "." + body), X-PrivateSign-Attempt. עד 8 ניסיונות ב-Exponential Backoff ואז Dead Letter (שליחה חוזרת מהמסך). servers: - url: http://127.0.0.1:8031/api/v1 security: - bearer: [] components: securitySchemes: bearer: { type: http, scheme: bearer } parameters: Idem: { name: Idempotency-Key, in: header, schema: { type: string }, required: false } schemas: Error: type: object properties: { error: { type: object, properties: { code: { type: string }, message: { type: string } } }, correlation_id: { type: string } } Policy: type: object properties: signature_type: { type: string, enum: [basic, enhanced], default: basic } auth_method: { type: string, enum: [link, code, otp_email, otp_sms, otp_whatsapp], default: link } routing: { type: string, enum: [serial, parallel, hybrid], default: serial } link_ttl_hours: { type: integer, default: 168 } reminder_after_hours: { type: integer, default: 48 } reminder_max: { type: integer, default: 3 } retention_days: { type: integer, default: 2555 } allow_download: { type: boolean, default: true } allow_decline: { type: boolean, default: true } org_seal_on_complete: { type: boolean, default: true } evidence_ip_ua: { type: boolean, default: true } Participant: type: object required: [name] properties: key: { type: string, description: מזהה לוגי לשיוך שדות } name: { type: string } email: { type: string } phone: { type: string } role: { type: string, enum: [signer, approver, filler, witness, viewer, cc], default: signer } step: { type: integer, default: 1 } lang: { type: string, enum: [he, en, ar, ru, fr], default: he } channel: { type: string, enum: [email, sms, whatsapp], default: email } message: { type: string } can_download: { type: boolean, default: true } id_number: { type: string, description: ת.ז. (9 ספרות + ספרת ביקורת) } Field: type: object required: [x, y] properties: document_index: { type: integer, default: 0 } participant_key: { type: string } type: { type: string, enum: [signature, initials, text, textarea, number, amount, percent, date, phone, email, address, id_number, checkbox, select, readonly, prefilled, note, stamp], default: signature } page: { type: integer, default: 1 } x: { type: number, description: שבר 0..1 מרוחב העמוד (משמאל) } y: { type: number, description: שבר 0..1 מגובה העמוד (מלמעלה) } w: { type: number, default: 0.2 } h: { type: number, default: 0.06 } required: { type: boolean, default: true } label: { type: string } options: { type: object, description: "choices: 'א|ב|ג', min, max, pattern" } value: { type: string, description: ערך ממולא מראש } EnvelopeCreate: type: object required: [title] properties: title: { type: string } lang: { type: string, default: he } template_id: { type: string, description: יצירה מתבנית (אז documents/fields נלקחים מהתבנית) } role_overrides: { type: object, description: "{role_key: {name,email,phone,lang,channel}}" } prefill: { type: object, description: "{field_label: value}" } tags: { type: array, items: { type: string } } documents: type: array items: { type: object, required: [content_base64], properties: { name: { type: string }, content_base64: { type: string }, kind: { type: string, enum: [sign, view], default: sign } } } participants: { type: array, items: { $ref: '#/components/schemas/Participant' } } fields: { type: array, items: { $ref: '#/components/schemas/Field' } } policy: { $ref: '#/components/schemas/Policy' } message_subject: { type: string } message_body: { type: string } send: { type: boolean, default: false } Envelope: type: object properties: id: { type: string } title: { type: string } status: { type: string, enum: [draft, scheduled, preparing, sent, delivered, opened, awaiting_auth, filling, awaiting_next, awaiting_approval, returned, completed, declined, cancelled, expired, delivery_failed, archived, legal_hold] } version: { type: integer } created_at: { type: string, format: date-time } sent_at: { type: string, format: date-time, nullable: true } completed_at: { type: string, format: date-time, nullable: true } expires_at: { type: string, format: date-time, nullable: true } policy: { $ref: '#/components/schemas/Policy' } participants: { type: array, items: { type: object } } documents: { type: array, items: { type: object, properties: { id: { type: string }, name: { type: string }, kind: { type: string }, version: { type: integer }, sha256: { type: string }, page_count: { type: integer } } } } evidence_available: { type: boolean } WebhookPayload: type: object properties: event_id: { type: string } event: { type: string, enum: [envelope.created, envelope.sent, delivery.delivered, delivery.failed, signer.viewed, signer.authentication_succeeded, signer.authentication_failed, signer.completed, signer.declined, envelope.completed, envelope.expired, envelope.cancelled, document.finalized, evidence.available, envelope.returned, form.submitted, payment.completed] } timestamp: { type: string, format: date-time } organization_id: { type: string } envelope_id: { type: string } data: { type: object } paths: /envelopes: get: summary: רשימת מעטפות (Pagination בסמן created_at) parameters: - { name: status, in: query, schema: { type: string } } - { name: limit, in: query, schema: { type: integer, maximum: 100, default: 25 } } - { name: cursor, in: query, schema: { type: string } } responses: "200": { description: OK, content: { application/json: { schema: { type: object, properties: { items: { type: array, items: { $ref: '#/components/schemas/Envelope' } }, next_cursor: { type: string, nullable: true } } } } } } post: summary: יצירת מעטפה (מסמכים, משתתפים, שדות, מדיניות) ושליחה אופציונלית parameters: [ { $ref: '#/components/parameters/Idem' } ] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/EnvelopeCreate' } } } } responses: "201": { description: נוצר, content: { application/json: { schema: { $ref: '#/components/schemas/Envelope' } } } } "400": { description: שגיאת קלט, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } } "409": { description: Idempotency-Key עם payload שונה } "422": { description: שגיאת מנוע (למשל חותם ללא שדה חתימה) } /envelopes/{id}: get: summary: סטטוס מעטפה parameters: [ { name: id, in: path, required: true, schema: { type: string } } ] responses: { "200": { description: OK, content: { application/json: { schema: { $ref: '#/components/schemas/Envelope' } } } }, "404": { description: לא נמצא (גם אם שייך לארגון אחר) } } /envelopes/{id}/send: post: { summary: שליחה, parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { $ref: '#/components/parameters/Idem' } ], responses: { "200": { description: נשלח } } } /envelopes/{id}/cancel: post: { summary: ביטול ונעילת קישורים, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], requestBody: { content: { application/json: { schema: { type: object, properties: { reason: { type: string } } } } } }, responses: { "200": { description: בוטל } } } /envelopes/{id}/remind: post: { summary: תזכורת למשתתפים שתורם הגיע, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: "{reminded: n}" } } } /envelopes/{id}/signing-links: get: { summary: קישורים חד-פעמיים חדשים (iframe/SDK/קיוסק) — מבטל קודמים, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: "{links: [{participant_id, name, url}]}" } } } /envelopes/{id}/documents/{doc}/download: get: { summary: הורדת מסמך (סופי חתום אם הושלם), parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { name: doc, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: PDF } } } /envelopes/{id}/evidence: get: { summary: חבילת ראיות (ZIP) או evidence.json עם ?format=json, parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { name: format, in: query, schema: { type: string, enum: [zip, json] } } ], responses: { "200": { description: ZIP/JSON }, "404": { description: טרם זמין } } } /oauth/token: post: summary: OAuth 2.0 Client Credentials → access token (שעה) security: [] requestBody: { content: { application/x-www-form-urlencoded: { schema: { type: object, required: [grant_type, client_id, client_secret], properties: { grant_type: { type: string, enum: [client_credentials] }, client_id: { type: string }, client_secret: { type: string }, scope: { type: string } } } } } } responses: { "200": { description: "{access_token, token_type, expires_in, scope}" }, "401": { description: invalid_client } } /templates: get: { summary: רשימת תבניות עם תפקידים ותוויות למילוי מקדים, responses: { "200": { description: "{items: [{id, name, category, version, roles[], prefill_labels[]}]}" } } } /bulk: post: summary: שליחה המונית מתבנית (אצווה מדורגת, עד 2000 שורות) parameters: [ { $ref: '#/components/parameters/Idem' } ] requestBody: { required: true, content: { application/json: { schema: { type: object, required: [template_id, rows], properties: { template_id: { type: string }, name: { type: string }, start: { type: boolean, default: true }, rows: { type: array, items: { type: object, properties: { title: { type: string }, roles: { type: object, additionalProperties: { $ref: '#/components/schemas/Participant' } }, prefill: { type: object, additionalProperties: { type: string } } } } } } } } } } responses: { "202": { description: "{batch_id, rows, invalid_rows[], status}" } } /bulk/{id}: get: { summary: מצב אצווה ושורותיה, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: OK } } } /envelopes/{id}/participants/{pid}/replace: post: { summary: החלפת משתתף (הקישור הקודם מתבטל), parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { name: pid, in: path, required: true, schema: { type: string } } ], requestBody: { content: { application/json: { schema: { type: object, required: [name], properties: { name: { type: string }, email: { type: string }, phone: { type: string }, channel: { type: string }, reason: { type: string } } } } } }, responses: { "200": { description: OK } } } /envelopes/{id}/attachments/{aid}: get: { summary: הורדת צרופה/צילום תעודה, parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { name: aid, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: file } } } /contacts: post: { summary: יצירת איש קשר, requestBody: { content: { application/json: { schema: { type: object, required: [name], properties: { name: { type: string }, email: { type: string }, phone: { type: string }, company: { type: string }, lang: { type: string } } } } } }, responses: { "201": { description: "{id}" } } } /envelopes/{id}/ai: get: { summary: "רשימת הצעות AI למעטפה (הצעות בלבד — אינן מוחלות ללא אישור)", parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: OK } } } /envelopes/{id}/ai/{kind}: post: { summary: "יצירת הצעת AI (fields | order | missing | extract | summary). התוצאה נשמרת כ-proposed ואינה משנה את המעטפה", parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { name: kind, in: path, required: true, schema: { type: string, enum: [fields, order, missing, extract, summary] } } ], responses: { "201": { description: "{id, kind, provider, status: proposed, result}" }, "409": { description: "AI לא זמין / כבוי בארגון" } } } /envelopes/{id}/ai/{sid}/accept: post: { summary: "החלת הצעה — פעולה אנושית מפורשת. selected = אינדקסים של הפריטים להחלה (ברירת מחדל: הכול)", parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { name: sid, in: path, required: true, schema: { type: string } } ], requestBody: { content: { application/json: { schema: { type: object, properties: { selected: { type: array, items: { type: integer } } } } } } }, responses: { "200": { description: "{id, status: accepted, applied}" }, "409": { description: "כבר הוכרעה / לא טיוטה" } } } /envelopes/{id}/ai/{sid}/reject: post: { summary: דחיית הצעה, parameters: [ { name: id, in: path, required: true, schema: { type: string } }, { name: sid, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: OK } } } /webhooks/events: get: { summary: רשימת אירועי Webhook ופרטי חתימה, responses: { "200": { description: OK } } }