Applications & Permissions

Which apps a caller can see or favorite, and the permissions behind that.

Apps catalogue

GET /applications

List every app you can access

User key

Example request

curl -X GET "https://api.openstudio.one/v1/applications" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/applications');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/applications", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/applications', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to applications. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
sections array of objects — One entry per sidebar divider (e.g. "Administration", "Data") — only dividers with at least one visible app underneath are included.
↳key string — This section's own internal identifier — not translated, not guaranteed stable across catalog changes.
↳title string — Same identifier as key for a section specifically (sections have no separate display value here) — already resolved to your account's language for apps' own title, see below.
↳apps array of objects — Every visible app/sub-heading under this section, in the same order the web sidebar itself shows them.
↳id integer — An internal numeric identifier for this app — the same value the web dashboard's own favorites widget keys its per-app color palette on (id % 7 against a fixed 7-color set), included so a client can mirror that exactly rather than picking colors some other way. Not meaningful for anything else — key is still the identifier every other endpoint (favorites, etc.) expects.
↳key string — This app's own internal identifier — the value POST /v1/favorites expects as key when can_favorite is true.
↳title string — Display name, already resolved to your account's own language — render as-is.
↳url string — The web dashboard's own internal address for this app. NOT the same string as key for most apps.
↳url_type string — external opens url directly (already a full link); view means url is a value on the web dashboard's own domain, not a standalone URL. Prefer mobile_integration below for deciding HOW to open an app on mobile — this field alone conflates several cases mobile_integration distinguishes (see its own description).
view
external
↳mobile_integration string — Admin-controlled — how the mobile app should open this specific app (see migrations/024_applications_mobile_integration.sql for the full decision table). native: a real native screen exists. web_os: opens in-app, attempts SSO sign-in (the default). web_ext: opens in-app, but the sign-in bridge is deliberately skipped (out of the OpenStudio session's scope). external: a true third-party link — opens in-app with no sign-in attempt, same handling as web_ext but a PERMANENT classification ("will likely never integrate") rather than "not yet." dashboard_os: a secondary OpenStudio-hosted dashboard under its own top-level route (not the usual ?view= convention) — still attempts SSO, just via url directly instead of /?view={key}. Not meaningful on a node that has children (a collapsible group, not a real destination).
native
web_os
web_ext
external
dashboard_os
↳icon string — A raw Font Awesome class name, e.g. "fa-address-book" — matches the icon the web dashboard itself shows for this app. Free-form per app, not a fixed enum — the catalog spans dozens of distinct icons across tenants; render your own fallback for anything you don't recognize rather than assuming full coverage.
↳status integer — 1 = live (generally available). 0 = beta (visible only to callers in the beta-tester group, same gating the web sidebar itself applies before this app is ever included in the response — a caller outside that group will simply never see a 0 here). -1 = maintenance (visible, but expect the app itself to be degraded/unavailable). -2 = dev (alpha/internal-only, same group-gating as beta, one level more restricted).
1
0
-1
-2
↳can_favorite boolean — true: a valid POST /v1/favorites target. false: shown here (e.g. for browsing/navigation) but rejected as a favorite — typically a parent/administrative entry rather than something a user would pin to their Home screen. There is no third state.
↳description string A short public-facing blurb, when this app has one. null, not "", when absent.
↳children array of objects — This app's own sub-apps, same object shape as this level, one level deep only (a sub-app's own children is never populated — this catalog doesn't nest further than that). Key is ABSENT (not an empty array) when this app has no sub-apps.

Example response

{
    "success": true,
    "data": {
        "sections": [
            {
                "key": "address_book_title",
                "title": "address_book_title",
                "apps": [
                    {
                        "key": "address_book_title",
                        "title": "address_book_title",
                        "url": "address_book",
                        "url_type": "internal",
                        "icon": "fa-address-book",
                        "status": 1,
                        "can_favorite": true,
                        "description": null
                    }
                ]
            }
        ]
    },
    "error": null
}

GET /favorites

List your favorite apps

User key

Example request

curl -X GET "https://api.openstudio.one/v1/favorites" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/favorites');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/favorites", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/favorites', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to favorites. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
favorites array of strings — App keys, in order.

Example response

{
    "success": true,
    "data": {
        "favorites": [
            "trouble_ticket_app",
            "address_book_title"
        ]
    },
    "error": null
}

POST /favorites

Add or remove a favorite app

User key

Request body

FieldTypeFlagsRequiredNotes
key string — Required An app key from GET /v1/applications (must have can_favorite: true) or a native-screen shortcut key.

Example request

curl -X POST "https://api.openstudio.one/v1/favorites" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/favorites');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'key' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'key': '...',
}
response = requests.post("https://api.openstudio.one/v1/favorites", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/favorites', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'key': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
action string — Whether this call added or removed the app from the caller's favorites.
added
removed
favorites array of strings — The full updated list, in order.

Example response

{
    "success": true,
    "data": {
        "action": "added",
        "favorites": [
            "trouble_ticket_app",
            "address_book_title"
        ]
    },
    "error": null
}

PATCH /favorites

Reorder your favorite apps

User key

Request body

FieldTypeFlagsRequiredNotes
order array of strings — Required The full, reordered list of favorited app keys, in the new display order.

Example request

curl -X PATCH "https://api.openstudio.one/v1/favorites" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"order":["..."]}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/favorites');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'order' => [
        '0' => '...',
    ],
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'order': [
        '...',
    ],
}
response = requests.patch("https://api.openstudio.one/v1/favorites", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/favorites', {
  method: 'PATCH',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'order': [
      '...',
    ],
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
favorites array of strings — The full list in its new order.

Example response

{
    "success": true,
    "data": {
        "favorites": [
            "address_book_title",
            "trouble_ticket_app"
        ]
    },
    "error": null
}

IT Protocol / Documents Management

Dashboard

GET /protocol/dashboard

Get the IT Protocol app's own dashboard

User key
Query parameters (1)

Other

ParameterTypeRequiredNotes
?uorstringOptionalScope stats.office to one specific unit from available_uors (matched by code), instead of the default aggregated view across every unit you belong to. Silently falls back to the aggregated view if the value isn't one of your own available_uors.

Example request

curl -X GET "https://api.openstudio.one/v1/protocol/dashboard?uor=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol/dashboard?uor=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol/dashboard?uor=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol/dashboard?uor=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol/dashboard. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
stats object — Your two document-count breakdowns — see personal/office below.
↳personal object — Your own RPA/CC/folder standing.
↳office object — Your organizational unit(s)' own standing — label names which unit(s) this breakdown covers (every unit you belong to, aggregated, unless uor narrowed it to one).
recent_items array of objects — Up to 6 most-recently-viewed protocol documents/dossiers, newest first.
↳doc_type string — Which detail endpoint this item belongs to — protocol items open via GET /protocol-documents/{doc_id}; dossier items have no detail endpoint yet.
protocol
dossier
↳doc_id integer The id to pass to the relevant detail endpoint. Null only if the underlying record was deleted after being viewed.
↳icon string — A semantic hint (e.g. inbound/outbound/internal/register/folder), not a font/icon-set name — render your own icon per value.
↳color string — A semantic color hint, not a hex value — map to your own palette.
accent
ok
purple
warn
muted
↳label string — Protocol number (e.g. 00015/2026) or register/dossier identifier, already formatted.
↳subject string The document/dossier's own subject line, as entered at registration.
↳viewed_at string — MySQL datetime, UTC.
available_uors array of objects — Every unit you belong to — valid values for the uor query param above. Empty if you don't belong to any (the office breakdown is then meaningless and can be hidden entirely).
↳code string — The unit's short code — pass this as uor.
↳title string Display name, when resolvable.

Example response

{
    "success": true,
    "data": {
        "stats": {
            "personal": {
                "rpa": {
                    "new": 2,
                    "tot": 14
                },
                "cc_direct": {
                    "new": 0,
                    "tot": 5
                },
                "cc_uor": {
                    "new": 1,
                    "tot": 9
                },
                "drafts": 1,
                "folders_rpa": {
                    "open": 3,
                    "closed": 7
                },
                "folders_cc": {
                    "open": 0,
                    "closed": 2
                },
                "to_file": 0,
                "returned": 0
            },
            "office": {
                "rpa": {
                    "new": 4,
                    "tot": 40
                },
                "cc_uor": {
                    "new": 1,
                    "tot": 9
                },
                "folders_rpa": {
                    "open": 6,
                    "closed": 15
                },
                "folders_cc": {
                    "open": 0,
                    "closed": 2
                },
                "to_file": 2,
                "returned": 0,
                "label": "All My Units"
            }
        },
        "recent_items": [
            {
                "doc_type": "protocol",
                "doc_id": 512,
                "icon": "inbound",
                "color": "accent",
                "label": "00015/2026",
                "subject": "Request for information",
                "viewed_at": "2026-08-26 09:12:00"
            }
        ],
        "available_uors": [
            {
                "code": "AFA",
                "title": "Administration Finance & Accounting"
            }
        ]
    },
    "error": null
}

Documents

GET /protocol-documents/{id}

Get a protocol document — full detail view

User key

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-documents/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-documents/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-documents/{id}. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
document object — Core fields — id, box, display_number (zerofilled), date, oggetto (subject), status, visibility level, etc.
classification object — The document's classification — see also GET /reference/protocol-classifications for the full pickable list.
↳var string — The identifier to submit back to POST /protocol-documents/{id}/change-classification (as var) or POST /protocol-registration (as classification) — distinct from the human-facing code below.
↳code string — The human-facing roman-numeral/index pair (e.g. I/4) — matches a classificazione_specifica row's own titolo/indice.
↳label string — The specific classification's own display title, already resolved via _lang() — never the raw underlying label value, which isn't the real display text.
↳general_label string The broader general-classification category this specific one rolls up into (e.g. code I/4 belongs to general category I), also _lang()-resolved.
↳sensitive boolean — Whether this document is flagged as containing sensitive personal information.
correspondent object Sender (arrival/internal) or recipient(s) (departure — recipients array for a multi-recipient document). A sender/recipient carries its own record_id — the registry id to submit back as correspondent_record_id on a reply/duplicate registration.
attachments array of objects — File list — id (when present) is usable with GET /protocol-documents/{id}/files/{file_id}/download to view/download that one file, or use GET .../download-all for a ZIP of everything.
↳id integer The underlying fileManager.fileId, when this attachment uses the modern storage path — null for a legacy raw-URL attachment (not individually downloadable, only via download-all).
↳filename string — The original filename.
↳archived boolean — Whether the underlying file has been archived or deleted in storage — the entry still appears here for a complete record, but the file itself may no longer be retrievable.
deadlines array of objects — Every deadline you can see on this document — your own personal reminders plus every shared one, matching GET /protocol-documents/{id}/deadlines' own visibility rule.
↳id integer — Use this in the deadline sub-routes below.
↳type string — A personal deadline is visible only to its own creator; a shared one is visible to anyone who can see the document.
personal
shared
↳deadline_date string — YYYY-MM-DD — when this deadline is due.
↳reminder_date string YYYY-MM-DD — an optional earlier reminder date, if one was set.
↳description string — What this deadline is for.
↳notes string — Free-text notes, separate from description.
↳completed boolean — Whether this deadline has been marked done.
↳completed_by integer The completing user's personal code, when completed is true.
↳completed_at string MySQL datetime, UTC, when completed is true.
↳can_edit boolean — Whether YOU can toggle/delete this specific deadline — its own creator always can; a shared deadline can also be edited by anyone with action_on_doc/founder/RPA standing.
responsibility object — Either rpa (arrival/departure) or author+original_rpa (internal), plus cc — an array of CC recipients, each with can_remove. Every person object carries avatar_url (their real photo, when one exists) and dep_title as the FULL Area > Department > Unit hierarchy, not just the immediate structure name.
folders array of objects — Folders (dossiers) this document is linked into.
↳id integer — The dossier id — use this for the unlink route below.
↳label string — The folder's own display number (id_fascicolo/anno).
↳subject string — The folder's own subject line.
workflow array of objects — The document's own workflow log (currently only ever gains a single close_workflow entry — see the close-workflow route below).
history array of objects — The full audit trail for this document — every write action taken on it, newest first.
notes array of objects — The annotation thread — private notes from OTHER people are already filtered out server-side.
↳id integer — This note's own id.
↳user_id integer — The author's personal code.
↳user_name string — The author's display name.
↳note string — The note text.
↳private boolean — Whether this note is visible only to its own author (you'll only ever see someone else's private note if it's your own).
↳is_me boolean — Whether YOU are this note's author — lets a client style your own notes differently, same as a chat thread.
↳created_at string — MySQL datetime, UTC.
retention object — The document's data-retention/conservation policy — policy (e.g. 10_years), expires_at, action (what happens on expiry), migrated/migrated_at (whether it's already been moved to cold storage).
integrity object — The document's tamper-evidence seal status.
↳sealed boolean — Whether a digest has ever been generated for this document — false for a legacy, never-sealed record.
↳digest string The current digest value, when sealed.
register object Present only when this document has been promoted onto a register — id, name, repno (the register-sequence number), repdate.
can object — One boolean per tool on the source page — see this route's own description for what true on a not-yet-writable one means.

Example response

{
    "success": true,
    "data": {
        "document": {
            "id": 512,
            "box": "arrivo",
            "display_number": "00015/2026",
            "date": "2026-08-20",
            "oggetto": "Request for information",
            "status": 1,
            "q_visibility": 0
        },
        "classification": {
            "code": "I/4",
            "label": "IT security",
            "general_label": "Administration",
            "sensitive": false
        },
        "correspondent": {
            "label": "Sender",
            "name": "Jane Doe",
            "sub": "Rome",
            "email": "jane@example.com"
        },
        "attachments": [],
        "deadlines": [],
        "responsibility": {
            "rpa": {
                "dep": "AFA",
                "user_id": 10000002,
                "user_name": "John Smith"
            },
            "cc": []
        },
        "folders": [],
        "workflow": [],
        "history": [],
        "notes": [],
        "retention": {
            "policy": "10_years",
            "migrated": false
        },
        "integrity": {
            "sealed": false,
            "digest": null
        },
        "register": null,
        "can": {
            "add_note": true,
            "add_cc": true,
            "close_workflow": true
        }
    },
    "error": null
}

POST /protocol-documents/{id}/notes

Add a note/annotation to a document

User key

Request body

FieldTypeFlagsRequiredNotes
note string — Required —
private boolean — Optional Visible only to you when true. Defaults to false.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/notes" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note":"...","private":true}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/notes');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'note' => '...',
    'private' => true,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'note': '...',
    'private': True,
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/notes", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/notes', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'note': '...',
    'private': true,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/cc

Add a CC recipient to a document

User key

Request body

FieldTypeFlagsRequiredNotes
dep string — Required A structure acronym.
user string — Required A personal code, or empty to CC the whole department (rare, matches the source page's own 'whole UOR/office' option).

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/cc" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dep":"...","user":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/cc');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'dep' => '...',
    'user' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'dep': '...',
    'user': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/cc", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/cc', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'dep': '...',
    'user': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

DELETE /protocol-documents/{id}/cc

Remove a CC recipient from a document

User key
Query parameters (2)

Other

ParameterTypeRequiredNotes
?depstringOptionalRequired — the structure acronym from the CC entry being removed.
?userstringOptionalRequired — the personal code from the CC entry being removed (empty string for a whole-department CC entry).

Example request

curl -X DELETE "https://api.openstudio.one/v1/protocol-documents/{id}/cc?dep=...&user=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/cc?dep=...&user=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.delete("https://api.openstudio.one/v1/protocol-documents/{id}/cc?dep=...&user=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/cc?dep=...&user=...', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/reject-assignment

Reject an arrival document's assignment

User key

Request body

FieldTypeFlagsRequiredNotes
reason string — Required Why the assignment is being rejected — recorded in the document history.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/reject-assignment" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/reject-assignment');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'reason' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'reason': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/reject-assignment", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/reject-assignment', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'reason': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/change-classification

Change a document's classification

User key

Request body

FieldTypeFlagsRequiredNotes
var string — Required A real classification identifier, from GET /reference/protocol-classifications's specific[].var.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/change-classification" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"var":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/change-classification');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'var' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'var': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/change-classification", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/change-classification', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'var': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/request-cancellation

Request that a document be cancelled (voided)

User key

Request body

FieldTypeFlagsRequiredNotes
reason string — Required Why this document should be cancelled.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/request-cancellation" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/request-cancellation');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'reason' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'reason': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/request-cancellation", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/request-cancellation', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'reason': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/change-rpa

Reassign the document's Responsible (RPA)

User key

Request body

FieldTypeFlagsRequiredNotes
resp_dep string — Required The new RPA's structure acronym.
resp_user string — Required The new RPA's personal code.
move_old_rpa_to_cc boolean — Optional CC the outgoing RPA instead of dropping them from the document. Defaults to false.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/change-rpa" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"resp_dep":"...","resp_user":"...","move_old_rpa_to_cc":true}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/change-rpa');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'resp_dep' => '...',
    'resp_user' => '...',
    'move_old_rpa_to_cc' => true,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'resp_dep': '...',
    'resp_user': '...',
    'move_old_rpa_to_cc': True,
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/change-rpa", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/change-rpa', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'resp_dep': '...',
    'resp_user': '...',
    'move_old_rpa_to_cc': true,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/update-retention

Update a document's retention (conservation) policy

User key

Request body

FieldTypeFlagsRequiredNotes
policy string — Required permanent, or a number of years as a string, e.g. 10_years.
action string — Optional migrate or delete — what happens once the policy expires. Defaults to migrate.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/update-retention" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":"...","action":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/update-retention');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'policy' => '...',
    'action' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'policy': '...',
    'action': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/update-retention", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/update-retention', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'policy': '...',
    'action': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

GET /protocol-documents/{id}/registers

List the registers this document could be assigned to

User key

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-documents/{id}/registers" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/registers');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-documents/{id}/registers", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/registers', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-documents/{id}/registers. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
registers array of objects — —
↳id integer — —
↳name string — —
↳code string —

Example response

{
    "success": true,
    "data": {
        "registers": [
            {
                "id": 3,
                "name": "Contracts Register",
                "code": "CTR"
            }
        ]
    },
    "error": null
}

POST /protocol-documents/{id}/assign-register

Also file this document into a register

User key

Request body

FieldTypeFlagsRequiredNotes
register_id integer — Required —

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/assign-register" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"register_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/assign-register');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'register_id' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'register_id': 123,
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/assign-register", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/assign-register', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'register_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —
register_id integer — —
repno integer — The newly-assigned register entry number.
year integer — —

Example response

{
    "success": true,
    "data": {
        "success": true,
        "register_id": 3,
        "repno": 42,
        "year": 2026
    },
    "error": null
}

POST /protocol-documents/{id}/seal

Generate an integrity seal for a legacy document

User key

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/seal" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/seal');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/seal", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/seal', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

GET /protocol-documents/{id}/download-all

Download every attached file as a ZIP

User key

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-documents/{id}/download-all" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/download-all');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-documents/{id}/download-all", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/download-all', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-documents/{id}/download-all. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
type string — —
format string — —
description string — —

Example response

{
    "success": true,
    "data": {},
    "error": null
}

POST /protocol-documents/{id}/files

Attach a new file to an already-registered document

User key

Request body

FieldTypeFlagsRequiredNotes
file_base64 string — Required —
filename string — Required —

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/files" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"file_base64":"...","filename":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/files');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'file_base64' => '...',
    'filename' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'file_base64': '...',
    'filename': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/files", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/files', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'file_base64': '...',
    'filename': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
id integer — The new fileManager.fileId.
filename string — The name it was actually saved as — suffixed if a same-named file already existed.

Example response

{
    "success": true,
    "data": {
        "id": 421,
        "filename": "contract_signed.pdf"
    },
    "error": null
}

GET /protocol-documents/{id}/files/{file_id}/download

Download one attachment

User key

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-documents/{id}/files/{file_id}/download" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/files/{file_id}/download');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-documents/{id}/files/{file_id}/download", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/files/{file_id}/download', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-documents/{id}/files/{file_id}/download. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
type string — —
format string — —
description string — —

Example response

{
    "success": true,
    "data": {},
    "error": null
}

POST /protocol-documents/{id}/deadlines

Add a deadline to a document

User key

Request body

FieldTypeFlagsRequiredNotes
deadline_date string — Required YYYY-MM-DD.
description string — Optional What this deadline is for.
notes string — Optional Free-text notes, separate from description.
reminder_date string — Optional YYYY-MM-DD.
type string — Optional Defaults to personal.
personal
shared

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/deadlines" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deadline_date":"...","description":"...","notes":"...","reminder_date":"...","type":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/deadlines');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'deadline_date' => '...',
    'description' => '...',
    'notes' => '...',
    'reminder_date' => '...',
    'type' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'deadline_date': '...',
    'description': '...',
    'notes': '...',
    'reminder_date': '...',
    'type': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/deadlines", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/deadlines', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'deadline_date': '...',
    'description': '...',
    'notes': '...',
    'reminder_date': '...',
    'type': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.
type string — The type actually applied — may differ from the request, see description.

Example response

{
    "success": true,
    "data": {
        "success": true,
        "type": "personal"
    },
    "error": null
}

PATCH /protocol-documents/{id}/deadlines/{deadline_id}

Toggle a deadline complete/reopen

User key

Example request

curl -X PATCH "https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.patch("https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}', {
  method: 'PATCH',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.
completed boolean — The new state after toggling.

Example response

{
    "success": true,
    "data": {
        "success": true,
        "completed": true
    },
    "error": null
}

DELETE /protocol-documents/{id}/deadlines/{deadline_id}

Delete a deadline

User key

Example request

curl -X DELETE "https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.delete("https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/deadlines/{deadline_id}', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/close-workflow

Close a document's workflow

User key

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/close-workflow" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/close-workflow');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/close-workflow", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/close-workflow', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-documents/{id}/dossiers

Link a document to a folder (dossier)

User key

Request body

FieldTypeFlagsRequiredNotes
dossier_id integer — Required The target folder's own id (from GET /protocol-dossiers), not its display number.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-documents/{id}/dossiers" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dossier_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/dossiers');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'dossier_id' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'dossier_id': 123,
}
response = requests.post("https://api.openstudio.one/v1/protocol-documents/{id}/dossiers", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/dossiers', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'dossier_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

DELETE /protocol-documents/{id}/dossiers/{dossier_id}

Unlink a document from a folder (dossier)

User key

Example request

curl -X DELETE "https://api.openstudio.one/v1/protocol-documents/{id}/dossiers/{dossier_id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-documents/{id}/dossiers/{dossier_id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.delete("https://api.openstudio.one/v1/protocol-documents/{id}/dossiers/{dossier_id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-documents/{id}/dossiers/{dossier_id}', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

Classifications

GET /reference/protocol-classifications

Get the Protocol app's classification tree

User key

Example request

curl -X GET "https://api.openstudio.one/v1/reference/protocol-classifications" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/protocol-classifications');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/reference/protocol-classifications", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/reference/protocol-classifications', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to reference/protocol-classifications. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
general array of objects — The top-level category list.
↳id integer — —
↳titolo string — The roman-numeral group code (e.g. I) — matches specific[].titolo.
↳var string The lang_var label was resolved from.
↳label string — Display title, already _lang()-resolved.
specific array of objects — The full flat list of specific classifications — a document's own classification.code/.label always come from one row here.
↳id integer — —
↳code string — titolo/indice combined — matches GET /protocol-documents/{id}'s own classification.code.
↳titolo string — This row's own group code — matches a general[].titolo.
↳indice string — The sub-index within that group.
↳var string The lang_var label was resolved from — this is also the exact value a document's own classification.var stores.
↳label string — Display title, already _lang()-resolved.

Example response

{
    "success": true,
    "data": {
        "general": [
            {
                "id": 1,
                "titolo": "I",
                "var": "administration",
                "label": "Administration"
            }
        ],
        "specific": [
            {
                "id": 5,
                "code": "I/4",
                "titolo": "I",
                "indice": "4",
                "var": "IT_security",
                "label": "IT security"
            }
        ]
    },
    "error": null
}

Folders (Dossiers)

GET /protocol-dossiers

Search/list folders (dossiers)

User key
Query parameters (8)

Other

ParameterTypeRequiredNotes
?qstringOptionalSubstring match against subject, folder number, and notes.
?statusstringOptionalDefaults to open.
open
closed
all
?classificationstringOptionalExact match against a specific classification var (see GET /reference/protocol-classifications).
?my_rpabooleanOptionalOnly folders you personally own (RPA). Mirrors the Dashboard's own "Folders I manage" stat.
?my_ccbooleanOptionalOnly folders you're personally in CC on. Mirrors the Dashboard's own "Folders (CC)" stat.
?rpastringOptionalExact match against an arbitrary hr_id — App Support #572, used for scoping "which folders can this document link into" (RPA + classification alignment), distinct from my_rpa (always the caller's own id).
?exclude_doc_idintegerOptionalExcludes folders a given document is already linked into.
?peek_next_idbooleanOptionalA completely different, lightweight response shape — see the dedicated summary below. When set, every other param on this route is ignored.

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-dossiers?q=...&status=...&classification=...&my_rpa=true&my_cc=true&rpa=...&exclude_doc_id=123&peek_next_id=true" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers?q=...&status=...&classification=...&my_rpa=true&my_cc=true&rpa=...&exclude_doc_id=123&peek_next_id=true');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-dossiers?q=...&status=...&classification=...&my_rpa=true&my_cc=true&rpa=...&exclude_doc_id=123&peek_next_id=true", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers?q=...&status=...&classification=...&my_rpa=true&my_cc=true&rpa=...&exclude_doc_id=123&peek_next_id=true', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-dossiers. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
dossiers array of objects — Up to 200 results, newest folder-year/number first.
↳id integer — Use this for GET /protocol-dossiers/{id}.
↳label string — The folder's own display number (id_fascicolo/anno).
↳subject string — The folder's own subject/title.
↳rpa_user_id integer The owning person's personal code.
↳rpa_user_name string The owning person's display name.
↳uor string — The owning structure's acronym.
↳uor_title string Display name for uor, when resolvable.
↳status integer — 0 = open, 1 = closed.
0
1
↳document_count integer — How many documents are linked into this folder.
↳access_reason string — Why you can see this result (e.g. RPA (Owner), Department Membership (UOR), CC (Read Only)) — same reasons GET /protocol-dossiers/{id} itself reports.

Example response

{
    "success": true,
    "data": {
        "dossiers": [
            {
                "id": 88,
                "label": "12/2026",
                "subject": "Vendor contracts",
                "rpa_user_id": 10000002,
                "rpa_user_name": "John Smith",
                "uor": "AFA",
                "uor_title": "Administration Finance & Accounting",
                "status": 0,
                "document_count": 4,
                "access_reason": "Department Membership (UOR)"
            }
        ]
    },
    "error": null
}

POST /protocol-dossiers

Create a new folder (dossier)

User key

Request body

FieldTypeFlagsRequiredNotes
oggetto string — Required The subject/title.
classificazione string — Required A specific classification var, from GET /reference/protocol-classifications.
uor string — Required The owning structure's acronym.
rpa string — Required The owning user's personal code.
anno integer — Optional Defaults to the current year.
note string — Optional Free-text notes for the new folder.
q_visibility integer — Optional Defaults to 0 (public).
0
1
2
3
father_id integer — Optional Makes this a sub-folder of an existing ROOT folder you own — must itself have no parent and belong to you, same constraint as the source page's own picker.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-dossiers" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"oggetto":"...","classificazione":"...","uor":"...","rpa":"...","anno":123,"note":"...","q_visibility":123,"father_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'oggetto' => '...',
    'classificazione' => '...',
    'uor' => '...',
    'rpa' => '...',
    'anno' => 123,
    'note' => '...',
    'q_visibility' => 123,
    'father_id' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'oggetto': '...',
    'classificazione': '...',
    'uor': '...',
    'rpa': '...',
    'anno': 123,
    'note': '...',
    'q_visibility': 123,
    'father_id': 123,
}
response = requests.post("https://api.openstudio.one/v1/protocol-dossiers", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'oggetto': '...',
    'classificazione': '...',
    'uor': '...',
    'rpa': '...',
    'anno': 123,
    'note': '...',
    'q_visibility': 123,
    'father_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
id integer — The new folder's own id.
label string — The generated display number.

Example response

{
    "success": true,
    "data": {
        "id": 91,
        "label": "15/2026"
    },
    "error": null
}

GET /protocol-dossiers/{id}

Get a folder (dossier) — full detail view

User key

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-dossiers/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-dossiers/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-dossiers/{id}. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
dossier object — Core fields.
↳id integer — This folder's own id — use it for every sub-route below.
↳label string — Display number (id_fascicolo/anno).
↳subject string — The folder's own subject/title.
↳note string Free-text notes.
↳status integer — 0 = open, 1 = closed.
0
1
↳q_visibility integer — Same 0-3 visibility scale as a document's own document.q_visibility.
↳created_at string MySQL datetime, UTC.
↳closed_at string MySQL datetime, UTC, when status is 1.
classification object — The folder's classification.
↳code string — The titolo/indice pair, e.g. I/4.
↳label string — Already _lang()-resolved — see GET /reference/protocol-classifications's own note on why this isn't the raw underlying label value.
rpa object — The folder's owning structure + person.
↳dep string — The owning structure's acronym.
↳dep_title string Display name for dep, when resolvable.
↳user_id integer The owning person's personal code.
↳user_name string The owning person's display name.
created_by object — Who created this folder.
↳user_id integer The creator's personal code.
↳user_name string The creator's display name.
↳dep string The creator's own department at the time of creation.
cc array of objects — Every CC entry on this folder.
↳dep string — A structure acronym.
↳dep_title string Display name for dep, when resolvable.
↳user_id integer A personal code, or null for a whole-department CC entry.
↳user_name string The CC'd person's display name, when user_id is set.
↳can_remove boolean — Whether YOU can remove this specific CC entry.
documents array of objects — Every document linked into this folder.
↳id integer — Use this with GET /protocol-documents/{id}.
↳box string — The document's own type — arrivo/uscita/interno.
↳display_number string The document's own protocol number, when it has one (null for a register entry with no protocol number yet).
↳date string — The document's own registration date.
↳subject string — The document's own subject line.
↳mismatch boolean — True when this document's own department or classification has drifted from the folder's — the source page's own "align" tool (not yet implemented here, see this route's own can) fixes this.
parent object The folder this one is nested under, if any.
↳id integer — The parent folder's own id.
↳label string — Display number.
↳subject string — Subject/title.
children array of objects — Folders nested directly under this one.
↳id integer — The child folder's own id.
↳label string — Display number.
↳subject string — Subject/title.
notes array of objects — The annotation thread — same shape and same "others' private notes filtered out" rule as GET /protocol-documents/{id}'s own notes.
↳id integer — This note's own id.
↳user_id integer — The author's personal code.
↳user_name string — The author's display name.
↳note string — The note text.
↳private boolean — Whether this note is visible only to its own author.
↳is_me boolean — Whether YOU are this note's author.
↳created_at string — MySQL datetime, UTC.
history array of objects — The folder's own audit trail.
↳action string — What happened.
↳user_id integer Who did it.
↳user_name string The actor's display name.
↳user_structure string The actor's CURRENT structure (Area > Unit), resolved at read time.
↳created_at string — MySQL datetime, UTC.
access_reason string — Why you can see this folder — see this route's own description.
can object — One boolean per tool — true on change_rpa/change_classification/align_mismatched_documents means you have permission, not that a write endpoint exists yet for it (real, documented scope cut).

Example response

{
    "success": true,
    "data": {
        "dossier": {
            "id": 88,
            "label": "12/2026",
            "subject": "Vendor contracts",
            "note": null,
            "status": 0,
            "q_visibility": 0,
            "created_at": "2026-01-10 09:00:00",
            "closed_at": null
        },
        "classification": {
            "code": "I/4",
            "label": "IT security"
        },
        "rpa": {
            "dep": "AFA",
            "dep_title": "Administration Finance & Accounting",
            "user_id": 10000002,
            "user_name": "John Smith"
        },
        "created_by": {
            "user_id": 10000002,
            "user_name": "John Smith",
            "dep": "AFA"
        },
        "cc": [],
        "documents": [],
        "parent": null,
        "children": [],
        "notes": [],
        "history": [],
        "access_reason": "RPA (Owner)",
        "can": {
            "operate": true,
            "rename": true,
            "close": true
        }
    },
    "error": null
}

PATCH /protocol-dossiers/{id}

Update a folder's own subject/notes

User key

Request body

FieldTypeFlagsRequiredNotes
oggetto string — Optional Renames the folder.
note string — Optional Replaces the folder's own notes.

Example request

curl -X PATCH "https://api.openstudio.one/v1/protocol-dossiers/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"oggetto":"...","note":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'oggetto' => '...',
    'note' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'oggetto': '...',
    'note': '...',
}
response = requests.patch("https://api.openstudio.one/v1/protocol-dossiers/{id}", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}', {
  method: 'PATCH',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'oggetto': '...',
    'note': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-dossiers/{id}/close

Close a folder

User key

Request body

FieldTypeFlagsRequiredNotes
note string — Optional Appended to the folder's own notes as a closing remark.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-dossiers/{id}/close" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/close');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'note' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'note': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-dossiers/{id}/close", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/close', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'note': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-dossiers/{id}/reopen

Reopen a closed folder

User key

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-dossiers/{id}/reopen" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/reopen');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.post("https://api.openstudio.one/v1/protocol-dossiers/{id}/reopen", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/reopen', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-dossiers/{id}/cc

Add a CC entry to a folder

User key

Request body

FieldTypeFlagsRequiredNotes
dep string — Required A structure acronym.
user string — Optional A personal code. Omit to CC the whole department.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-dossiers/{id}/cc" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dep":"...","user":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/cc');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'dep' => '...',
    'user' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'dep': '...',
    'user': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-dossiers/{id}/cc", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/cc', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'dep': '...',
    'user': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

DELETE /protocol-dossiers/{id}/cc

Remove a CC entry from a folder

User key
Query parameters (2)

Other

ParameterTypeRequiredNotes
?depstringOptionalRequired.
?userstringOptionalRequired (empty string for a whole-department entry).

Example request

curl -X DELETE "https://api.openstudio.one/v1/protocol-dossiers/{id}/cc?dep=...&user=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/cc?dep=...&user=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.delete("https://api.openstudio.one/v1/protocol-dossiers/{id}/cc?dep=...&user=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/cc?dep=...&user=...', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-dossiers/{id}/notes

Add a note/annotation to a folder

User key

Request body

FieldTypeFlagsRequiredNotes
note string — Required The note text.
private boolean — Optional Visible only to you when true.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-dossiers/{id}/notes" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note":"...","private":true}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/notes');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'note' => '...',
    'private' => true,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'note': '...',
    'private': True,
}
response = requests.post("https://api.openstudio.one/v1/protocol-dossiers/{id}/notes", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/notes', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'note': '...',
    'private': true,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

GET /protocol-dossiers/{id}/eligible-documents

Search documents this folder could link

User key
Query parameters (1)

Other

ParameterTypeRequiredNotes
?qstringOptionalSubstring match against subject or protocol number.

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-dossiers/{id}/eligible-documents?q=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/eligible-documents?q=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-dossiers/{id}/eligible-documents?q=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/eligible-documents?q=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-dossiers/{id}/eligible-documents. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
documents array of objects — Up to 50 matches.
↳id integer — Pass this as doc_id to the link route.
↳box string — The document's own type — arrivo/uscita/interno.
↳display_number string The document's own protocol number, when it has one.
↳subject string — The document's own subject line.

Example response

{
    "success": true,
    "data": {
        "documents": [
            {
                "id": 512,
                "box": "arrivo",
                "display_number": "00015/2026",
                "subject": "Request for information"
            }
        ]
    },
    "error": null
}

POST /protocol-dossiers/{id}/documents

Link a document into a folder

User key

Request body

FieldTypeFlagsRequiredNotes
doc_id integer — Required From GET /protocol-dossiers/{id}/eligible-documents.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-dossiers/{id}/documents" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"doc_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/documents');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'doc_id' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'doc_id': 123,
}
response = requests.post("https://api.openstudio.one/v1/protocol-dossiers/{id}/documents", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/documents', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'doc_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

DELETE /protocol-dossiers/{id}/documents/{document_id}

Unlink a document from a folder

User key

Example request

curl -X DELETE "https://api.openstudio.one/v1/protocol-dossiers/{id}/documents/{document_id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/documents/{document_id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.delete("https://api.openstudio.one/v1/protocol-dossiers/{id}/documents/{document_id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/documents/{document_id}', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-dossiers/{id}/parent

Set or clear a folder's parent folder

User key

Request body

FieldTypeFlagsRequiredNotes
father_id integer — Optional Omit or 0 to clear.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-dossiers/{id}/parent" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"father_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-dossiers/{id}/parent');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'father_id' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'father_id': 123,
}
response = requests.post("https://api.openstudio.one/v1/protocol-dossiers/{id}/parent", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-dossiers/{id}/parent', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'father_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — Always true — a failed attempt returns an error response instead.

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

Registry

GET /registry

Search the Registry

User key
Query parameters (6)

Other

ParameterTypeRequiredNotes
?qstringOptionalSubstring match against the record id, first/last name, and the composite display name.
?typestringOptionalDefaults to all.
person
structure
all
?scopestringOptionalDefaults to all. internal means linked to a real system user/structure.
internal
external
all
?emailstringOptionalSubstring match against email or certified email (PEC).
?citystringOptionalSubstring match against home city, birth city, or home address.
?taxcodestringOptionalSubstring match against fiscal code or VAT number.

Example request

curl -X GET "https://api.openstudio.one/v1/registry?q=...&type=...&scope=...&email=...&city=...&taxcode=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/registry?q=...&type=...&scope=...&email=...&city=...&taxcode=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/registry?q=...&type=...&scope=...&email=...&city=...&taxcode=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/registry?q=...&type=...&scope=...&email=...&city=...&taxcode=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to registry. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
results array of objects — Up to 50 results, alphabetical by display name. Merged-away (duplicate) records are never returned.
↳record_id integer — This record's own id — use it for GET /registry/{record_id}.
↳display_number string — Zero-padded 5-digit display form of record_id.
↳name string — Composite display name.
↳type string — —
person
structure
↳is_internal boolean — Whether this record is linked to a real system user/structure.
↳system_id string The linked system id, when is_internal is true.
↳is_aligned boolean For an internal record: whether its own structure/responsible assignment currently matches one of its real system role contexts (department membership/leadership). Null for an external record — the concept doesn't apply.

Example response

{
    "success": true,
    "data": {
        "results": [
            {
                "record_id": 142,
                "display_number": "00142",
                "name": "Rossi Mario",
                "type": "person",
                "is_internal": true,
                "system_id": "10000002",
                "is_aligned": true
            }
        ]
    },
    "error": null
}

POST /registry

Create a new EXTERNAL Registry record

User key

Request body

FieldTypeFlagsRequiredNotes
type string — Required —
person
structure
first_name string — Optional Required for type=person.
last_name string — Optional Required for type=person.
name string — Optional Required for type=structure — the structure's own name.
sex string — Optional —
birth_date string — Optional YYYY-MM-DD. Person only.
birth_city string — Optional —
birth_province string — Optional —
birth_state string — Optional —
citizenship string — Optional —
role string — Optional Person only — their role/title.
structure_record_id integer Optional Person only — their membership structure, a real registry record id.
responsible_record_id integer Optional Structure only — its own responsible person, a real registry record id.
taxcode string — Optional —
vat_number string — Optional —
email string — Optional —
pec string — Optional —
website string — Optional —
phone_number string — Optional —
mobile_number string — Optional —
fax_number string — Optional —
home_address string — Optional —
home_city string — Optional —
home_district string — Optional —
home_country string — Optional —
home_postcode string — Optional —
note string — Optional —

Example request

curl -X POST "https://api.openstudio.one/v1/registry" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"...","first_name":"...","last_name":"...","name":"...","sex":"...","birth_date":"...","birth_city":"...","birth_province":"...","birth_state":"...","citizenship":"...","role":"...","structure_record_id":123,"responsible_record_id":123,"taxcode":"...","vat_number":"...","email":"...","pec":"...","website":"...","phone_number":"...","mobile_number":"...","fax_number":"...","home_address":"...","home_city":"...","home_district":"...","home_country":"...","home_postcode":"...","note":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/registry');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'type' => '...',
    'first_name' => '...',
    'last_name' => '...',
    'name' => '...',
    'sex' => '...',
    'birth_date' => '...',
    'birth_city' => '...',
    'birth_province' => '...',
    'birth_state' => '...',
    'citizenship' => '...',
    'role' => '...',
    'structure_record_id' => 123,
    'responsible_record_id' => 123,
    'taxcode' => '...',
    'vat_number' => '...',
    'email' => '...',
    'pec' => '...',
    'website' => '...',
    'phone_number' => '...',
    'mobile_number' => '...',
    'fax_number' => '...',
    'home_address' => '...',
    'home_city' => '...',
    'home_district' => '...',
    'home_country' => '...',
    'home_postcode' => '...',
    'note' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'type': '...',
    'first_name': '...',
    'last_name': '...',
    'name': '...',
    'sex': '...',
    'birth_date': '...',
    'birth_city': '...',
    'birth_province': '...',
    'birth_state': '...',
    'citizenship': '...',
    'role': '...',
    'structure_record_id': 123,
    'responsible_record_id': 123,
    'taxcode': '...',
    'vat_number': '...',
    'email': '...',
    'pec': '...',
    'website': '...',
    'phone_number': '...',
    'mobile_number': '...',
    'fax_number': '...',
    'home_address': '...',
    'home_city': '...',
    'home_district': '...',
    'home_country': '...',
    'home_postcode': '...',
    'note': '...',
}
response = requests.post("https://api.openstudio.one/v1/registry", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/registry', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'type': '...',
    'first_name': '...',
    'last_name': '...',
    'name': '...',
    'sex': '...',
    'birth_date': '...',
    'birth_city': '...',
    'birth_province': '...',
    'birth_state': '...',
    'citizenship': '...',
    'role': '...',
    'structure_record_id': 123,
    'responsible_record_id': 123,
    'taxcode': '...',
    'vat_number': '...',
    'email': '...',
    'pec': '...',
    'website': '...',
    'phone_number': '...',
    'mobile_number': '...',
    'fax_number': '...',
    'home_address': '...',
    'home_city': '...',
    'home_district': '...',
    'home_country': '...',
    'home_postcode': '...',
    'note': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
type string — —
description string — —

Example response

{
    "success": true,
    "data": {
        "record_id": 891,
        "display_number": "00891",
        "name": "Rossi Mario",
        "type": "person",
        "is_internal": false,
        "system_id": null
    },
    "error": null
}

GET /registry/{id}

Get a Registry record — full profile

User key

Example request

curl -X GET "https://api.openstudio.one/v1/registry/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/registry/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/registry/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/registry/{id}', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to registry/{id}. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
record_id integer — This record's own id.
name string — Composite display name.
type string — —
person
structure
is_internal boolean — Whether linked to a real system user/structure.
linked_uid integer The linked system user's own login id, when resolvable.
structure object — This record's own structure assignment.
↳record_id integer —
↳display string —
responsible object — This record's own responsible-person assignment.
↳record_id integer —
↳display string —
contexts array of objects — Real system role contexts (Founder/Area Manager/Dept. Leader/Employee) for an internal person — empty for a structure or an external/unlinked person.
↳role string — —
↳department_label string — —
↳reports_to object — —
↳status string — —
↳record_id integer —
↳label string — —
↳active boolean — Whether this specific context matches this record's own current structure/responsible assignment.
is_aligned boolean — Whether the structure/responsible assignment above currently matches a real system role context.
merged_survivor object If this record was merged into another (duplicate-merging isn't migrated here), the surviving record to redirect to. This record itself always stays resolvable — historical references must keep working.
mismatches array of objects — Fields that differ between this registry record and its linked system user, for POST /registry/{id}/sync. Empty when not internal, or when there's nothing to sync.
↳field string — —
↳registry_value string —
↳system_value string —
↳suggested_direction string — —
to_registry
to_system
can object — Your real edit/sync permission for THIS record — edit/sync booleans.

Example response

{
    "success": true,
    "data": {
        "record_id": 142,
        "name": "Rossi Mario",
        "type": "person",
        "is_internal": true,
        "linked_uid": 55,
        "structure": {
            "record_id": 12,
            "display": "IT Department"
        },
        "responsible": {
            "record_id": 8,
            "display": "Jane Doe"
        },
        "contexts": [],
        "is_aligned": true,
        "merged_survivor": null,
        "mismatches": [],
        "can": {
            "edit": true,
            "sync": true
        }
    },
    "error": null
}

PATCH /registry/{id}

Edit a Registry record

User key

Request body

FieldTypeFlagsRequiredNotes
first_name string — Optional —
last_name string — Optional —
name string — Optional For a structure record (type: "structure") only — its own single display name field.
taxcode string — Optional —
vat_number string — Optional —
sex string — Optional —
citizenship string — Optional —
citizenship_other string — Optional —
birth_date string — Optional YYYY-MM-DD, or null to clear.
birth_city string — Optional —
birth_province string — Optional —
birth_state string — Optional —
home_address string — Optional —
home_number string — Optional —
home_postcode string — Optional —
home_city string — Optional —
home_district string — Optional —
home_country string — Optional —
home_co string — Optional Care-of / attention-line, for the home address.
home_date string — Optional YYYY-MM-DD, or null to clear.
mobile_number string — Optional —
phone_number string — Optional —
fax_number string — Optional —
email string — Optional —
pec string — Optional Certified email (PEC), an Italian legal-mail concept — a real, distinct field from email.
note string — Optional —
structure_record_id integer — Optional Sets this record's own structure assignment — pass another registry record's id (or a resolvable system id), or null to clear.
responsible_record_id integer — Optional Sets this record's own responsible-person assignment, same resolution as structure_record_id.

Example request

curl -X PATCH "https://api.openstudio.one/v1/registry/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"...","last_name":"...","name":"...","taxcode":"...","vat_number":"...","sex":"...","citizenship":"...","citizenship_other":"...","birth_date":"...","birth_city":"...","birth_province":"...","birth_state":"...","home_address":"...","home_number":"...","home_postcode":"...","home_city":"...","home_district":"...","home_country":"...","home_co":"...","home_date":"...","mobile_number":"...","phone_number":"...","fax_number":"...","email":"...","pec":"...","note":"...","structure_record_id":123,"responsible_record_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/registry/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'first_name' => '...',
    'last_name' => '...',
    'name' => '...',
    'taxcode' => '...',
    'vat_number' => '...',
    'sex' => '...',
    'citizenship' => '...',
    'citizenship_other' => '...',
    'birth_date' => '...',
    'birth_city' => '...',
    'birth_province' => '...',
    'birth_state' => '...',
    'home_address' => '...',
    'home_number' => '...',
    'home_postcode' => '...',
    'home_city' => '...',
    'home_district' => '...',
    'home_country' => '...',
    'home_co' => '...',
    'home_date' => '...',
    'mobile_number' => '...',
    'phone_number' => '...',
    'fax_number' => '...',
    'email' => '...',
    'pec' => '...',
    'note' => '...',
    'structure_record_id' => 123,
    'responsible_record_id' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'first_name': '...',
    'last_name': '...',
    'name': '...',
    'taxcode': '...',
    'vat_number': '...',
    'sex': '...',
    'citizenship': '...',
    'citizenship_other': '...',
    'birth_date': '...',
    'birth_city': '...',
    'birth_province': '...',
    'birth_state': '...',
    'home_address': '...',
    'home_number': '...',
    'home_postcode': '...',
    'home_city': '...',
    'home_district': '...',
    'home_country': '...',
    'home_co': '...',
    'home_date': '...',
    'mobile_number': '...',
    'phone_number': '...',
    'fax_number': '...',
    'email': '...',
    'pec': '...',
    'note': '...',
    'structure_record_id': 123,
    'responsible_record_id': 123,
}
response = requests.patch("https://api.openstudio.one/v1/registry/{id}", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/registry/{id}', {
  method: 'PATCH',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'first_name': '...',
    'last_name': '...',
    'name': '...',
    'taxcode': '...',
    'vat_number': '...',
    'sex': '...',
    'citizenship': '...',
    'citizenship_other': '...',
    'birth_date': '...',
    'birth_city': '...',
    'birth_province': '...',
    'birth_state': '...',
    'home_address': '...',
    'home_number': '...',
    'home_postcode': '...',
    'home_city': '...',
    'home_district': '...',
    'home_country': '...',
    'home_co': '...',
    'home_date': '...',
    'mobile_number': '...',
    'phone_number': '...',
    'fax_number': '...',
    'email': '...',
    'pec': '...',
    'note': '...',
    'structure_record_id': 123,
    'responsible_record_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /registry/{id}/sync

Apply a Registry <-> system-user field sync

User key

Request body

FieldTypeFlagsRequiredNotes
fields array of objects — Required Each entry: {field, direction} — field is one of the names from GET /registry/{id}'s own mismatches, direction is to_registry (system user -> registry) or to_system (registry -> system user).

Example request

curl -X POST "https://api.openstudio.one/v1/registry/{id}/sync" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fields":[{}]}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/registry/{id}/sync');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'fields' => [
        '0' => [
        ],
    ],
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'fields': [
        {
        },
    ],
}
response = requests.post("https://api.openstudio.one/v1/registry/{id}/sync", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/registry/{id}/sync', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'fields': [
      {
      },
    ],
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

GET /protocol-search

Unified Protocol document search

User key
Query parameters (10)

Other

ParameterTypeRequiredNotes
?typestringOptionalDefaults to global (every box you have visibility into). A specific type 403s if you lack that box's own view permission.
global
arrival
departure
internal
register
?qstringOptionalSubstring/regex match against subject, classification, notes, keywords, attachment filenames, means of transmission, external protocol reference, and sender/recipient name or email.
?statusstringOptionalDefaults to active (everything except cancelled).
active
cancelled
returned
all
?date_fromstringOptionalYYYY-MM-DD, inclusive.
?date_tostringOptionalYYYY-MM-DD, inclusive.
?yearintegerOptionalMatches either the registration year or the original (imported) document year.
?classificationstringOptionalSubstring/regex match against the classification var.
?depstringOptionalA structure acronym — matches either the posting or the owning (RPA) department.
?rolestringOptionalDocuments where you are the RPA (mine_rpa), where you personally appear in the CC list (mine_cc), where one of your OWN structures appears in the CC list (uor_cc), or that you authored (mine_author) — mirrors the Dashboard widget's own 4 personal-tab links.
mine_rpa
mine_cc
uor_cc
mine_author
?in_folderstringOptionalWhether the document has already been placed into a folder. Mirrors the Dashboard's own "to be filed" stat when combined with role=mine_rpa.
yes
no

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-search?type=...&q=...&status=...&date_from=...&date_to=...&year=123&classification=...&dep=...&role=...&in_folder=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-search?type=...&q=...&status=...&date_from=...&date_to=...&year=123&classification=...&dep=...&role=...&in_folder=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-search?type=...&q=...&status=...&date_from=...&date_to=...&year=123&classification=...&dep=...&role=...&in_folder=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-search?type=...&q=...&status=...&date_from=...&date_to=...&year=123&classification=...&dep=...&role=...&in_folder=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-search. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
type string — The resolved search type (never global unresolved — reflects what was actually queried).
results array of objects — Up to 100 results, newest first.
↳id integer — Use this with GET /protocol-documents/{id}.
↳box string — The document's own type.
arrivo
uscita
interno
↳display_number string Protocol number, or register number when registered but not yet protocol-numbered. Null for a register-only entry with neither yet.
↳date string — MySQL datetime.
↳subject string — —
↳status integer — Raw status code (-1 cancelled, 3 returned, others active/workflow states).
↳status_label string — —
Active
Cancelled
Returned
↳classification string The classification var — resolve a real label via GET /reference/protocol-classifications.
↳is_register boolean — Whether this document also has a register entry.

Example response

{
    "success": true,
    "data": {
        "type": "global",
        "results": [
            {
                "id": 412,
                "box": "arrivo",
                "display_number": "00231/2026",
                "date": "2026-08-20 09:15:00",
                "subject": "Vendor invoice",
                "status": 0,
                "status_label": "Active",
                "classification": "I_4",
                "is_register": false
            }
        ]
    },
    "error": null
}

UOP Inbox

GET /protocol-uop-inbox

List the UOP (Protocol Office) incoming-mail inbox

User key
Query parameters (6)

Pagination

ParameterTypeRequiredNotes
?pageintegerOptional25 per page, defaults to 1.

Other

ParameterTypeRequiredNotes
?viewstringOptionalDefaults to pending (not yet triaged).
pending
history
spam
?qstringOptionalSubstring match against sender, subject, or body.
?mailboxstringOptionalExact match against one of mailboxes' own value.
?date_fromstringOptionalYYYY-MM-DD, inclusive.
?date_tostringOptionalYYYY-MM-DD, inclusive.

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-uop-inbox?view=...&q=...&mailbox=...&date_from=...&date_to=...&page=123" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-uop-inbox?view=...&q=...&mailbox=...&date_from=...&date_to=...&page=123');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-uop-inbox?view=...&q=...&mailbox=...&date_from=...&date_to=...&page=123", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-uop-inbox?view=...&q=...&mailbox=...&date_from=...&date_to=...&page=123', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-uop-inbox. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
view string — The resolved tab.
tab_counts object — Pending/history/spam counts, always for ALL tabs regardless of view.
↳pending integer — —
↳history integer — —
↳spam integer — —
items array of objects — —
↳id integer — Use this with GET /protocol-uop-inbox/{id}.
↳sender string — —
↳subject string — —
↳received_at string — MySQL datetime.
↳mailbox string The receiving mailbox's own display label, falling back to its raw address.
↳linked_doc_id integer Set once this email has already been registered as a Protocol document — use with GET /protocol-documents/{id}.
↳linked_prot_id string The linked document's own protocol number, when set.
total integer — —
page integer — —
total_pages integer — —
mailboxes array of objects — Every mailbox this brand has ever received into, for the mailbox filter.
↳value string — —
↳label string — —

Example response

{
    "success": true,
    "data": {
        "view": "pending",
        "tab_counts": {
            "pending": 4,
            "history": 120,
            "spam": 3
        },
        "items": [
            {
                "id": 55,
                "sender": "vendor@example.com",
                "subject": "Invoice attached",
                "received_at": "2026-08-20 09:00:00",
                "mailbox": "Protocol",
                "linked_doc_id": null,
                "linked_prot_id": null
            }
        ],
        "total": 4,
        "page": 1,
        "total_pages": 1,
        "mailboxes": [
            {
                "value": "protocollo@example.com",
                "label": "Protocol"
            }
        ]
    },
    "error": null
}

GET /protocol-uop-inbox/{id}

Preview one UOP inbox email

User key

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-uop-inbox/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-uop-inbox/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-uop-inbox/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-uop-inbox/{id}', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-uop-inbox/{id}. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
id integer — —
sender string — —
subject string — —
body string — Raw email HTML body, with <script> tags stripped.
received_at string — —
status string — —
new
registered
ignored
spam
files array of objects — —
↳id integer — A fileManager id — resolve via the FileManager, not a raw URL.
↳name string — —

Example response

{
    "success": true,
    "data": {
        "id": 55,
        "sender": "vendor@example.com",
        "subject": "Invoice attached",
        "body": "<p>Please find attached...</p>",
        "received_at": "2026-08-20 09:00:00",
        "status": "new",
        "files": [
            {
                "id": 901,
                "name": "invoice.pdf"
            }
        ]
    },
    "error": null
}

POST /protocol-uop-inbox/{id}/ignore

Archive a pending UOP inbox email

User key

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-uop-inbox/{id}/ignore" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-uop-inbox/{id}/ignore');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.post("https://api.openstudio.one/v1/protocol-uop-inbox/{id}/ignore", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-uop-inbox/{id}/ignore', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /protocol-uop-inbox/{id}/spam

Report a pending UOP inbox email as spam

User key

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-uop-inbox/{id}/spam" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-uop-inbox/{id}/spam');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.post("https://api.openstudio.one/v1/protocol-uop-inbox/{id}/spam", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-uop-inbox/{id}/spam', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

GET /protocol-uop-inbox/{id}/files/{file_id}/download

Download a UOP inbox email attachment

User key

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-uop-inbox/{id}/files/{file_id}/download" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-uop-inbox/{id}/files/{file_id}/download');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-uop-inbox/{id}/files/{file_id}/download", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-uop-inbox/{id}/files/{file_id}/download', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-uop-inbox/{id}/files/{file_id}/download. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
type string — —
description string — —

Example response

{
    "success": true,
    "data": {},
    "error": null
}

Cancellation Requests

GET /protocol-cancellation-requests

List document cancellation requests

User key
Query parameters (1)

Other

ParameterTypeRequiredNotes
?statusstringOptionalDefaults to pending.
pending
resolved

Example request

curl -X GET "https://api.openstudio.one/v1/protocol-cancellation-requests?status=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-cancellation-requests?status=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/protocol-cancellation-requests?status=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-cancellation-requests?status=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to protocol-cancellation-requests. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
status string — —
items array of objects — —
↳id integer — Use this with the approve/refuse routes below.
↳doc_id integer — Use with GET /protocol-documents/{id}.
↳document_display_number string —
↳document_date string —
↳requested_at string — —
↳requester_id string —
↳requester_name string —
↳reason string — —
↳status string — —
pending
approved
refused

Example response

{
    "success": true,
    "data": {
        "status": "pending",
        "items": [
            {
                "id": 12,
                "doc_id": 412,
                "document_display_number": "00231/2026",
                "document_date": "2026-08-20 09:15:00",
                "requested_at": "2026-08-25 10:00:00",
                "requester_id": "10000002",
                "requester_name": "John Smith",
                "reason": "Wrong recipient",
                "status": "pending"
            }
        ]
    },
    "error": null
}

POST /protocol-cancellation-requests/{id}/approve

Approve a cancellation request — voids the document

User key

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/approve" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/approve');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.post("https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/approve", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/approve', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —
doc_id integer — —

Example response

{
    "success": true,
    "data": {
        "success": true,
        "doc_id": 412
    },
    "error": null
}

POST /protocol-cancellation-requests/{id}/refuse

Refuse a cancellation request — document stays as-is

User key

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/refuse" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/refuse');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.post("https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/refuse", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-cancellation-requests/{id}/refuse', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —
doc_id integer — —

Example response

{
    "success": true,
    "data": {
        "success": true,
        "doc_id": 412
    },
    "error": null
}

Registration

POST /protocol-registration

Register a new Protocol document (Arrival/Departure/Internal)

User key

Request body

FieldTypeFlagsRequiredNotes
box string — Required —
arrival
departure
internal
subject string — Required —
classification string — Required A specific classification var, from GET /reference/protocol-classifications.
correspondent_record_id integer — Optional A Registry record id (GET /registry) — required for arrival (the sender) and departure (the recipient); not used for internal.
resp_dep string — Optional The RPA's own structure acronym — unrestricted (any real department, see GET /reference/protocol-structure-people for who's assignable within it). Defaults to your own primary structure.
resp_user string — Optional The RPA person's personal code. Defaults to you.
posted_by_dep string — Optional Which UOR you're registering this document ON BEHALF OF — a real, SEPARATE field from resp_dep/resp_user above. Must be one of GET /reference/protocol-manageable-uors' own list (your primary department, or a UOR you hold a real Level-2 management grant on) — a 403 otherwise. Defaults to your own primary department.
routed_to_dep string — Optional For an internal document: the receiving structure's acronym.
routed_to_user string — Optional For an internal document: the receiving person's personal code.
note string — Optional —
keywords string — Optional —
transmission_means string — Optional How this arrived/was sent (mail, PEC, hand-delivered, etc).
external_reference string — Optional The sender's own protocol reference, when known.
visibility integer — Optional Defaults to 0 (public).
0
1
2
3
sensitive boolean — Optional —
cc array — Optional CC recipients at creation time — an array of {dep, user}, each a real department acronym + personal code pair.
retention_policy string — Optional —
retention_action string — Optional What happens once retention expires — coerced to delete when no cold-storage endpoint is configured (see GET /reference/protocol-manageable-uors' own has_storage_endpoint).
external_reference_date string — Optional The correspondent's own reference DATE (YYYY-MM-DD) — distinct from external_reference (their reference NUMBER). No dedicated column on web either; appended to note as a plain annotation, mirrored exactly here.
original_date string — Optional Backdated/late ("deferred") registration — the document's real original arrival date (YYYY-MM-DD), stored in repdate. Requires reason_delay alongside it.
reason_delay string — Optional Required alongside original_date — why this is being registered late. Appended to note as a plain annotation, same as web.

Example request

curl -X POST "https://api.openstudio.one/v1/protocol-registration" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"box":"...","subject":"...","classification":"...","correspondent_record_id":123,"resp_dep":"...","resp_user":"...","posted_by_dep":"...","routed_to_dep":"...","routed_to_user":"...","note":"...","keywords":"...","transmission_means":"...","external_reference":"...","visibility":123,"sensitive":true,"cc":["..."],"retention_policy":"...","retention_action":"...","external_reference_date":"...","original_date":"...","reason_delay":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/protocol-registration');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'box' => '...',
    'subject' => '...',
    'classification' => '...',
    'correspondent_record_id' => 123,
    'resp_dep' => '...',
    'resp_user' => '...',
    'posted_by_dep' => '...',
    'routed_to_dep' => '...',
    'routed_to_user' => '...',
    'note' => '...',
    'keywords' => '...',
    'transmission_means' => '...',
    'external_reference' => '...',
    'visibility' => 123,
    'sensitive' => true,
    'cc' => [
        '0' => '...',
    ],
    'retention_policy' => '...',
    'retention_action' => '...',
    'external_reference_date' => '...',
    'original_date' => '...',
    'reason_delay' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'box': '...',
    'subject': '...',
    'classification': '...',
    'correspondent_record_id': 123,
    'resp_dep': '...',
    'resp_user': '...',
    'posted_by_dep': '...',
    'routed_to_dep': '...',
    'routed_to_user': '...',
    'note': '...',
    'keywords': '...',
    'transmission_means': '...',
    'external_reference': '...',
    'visibility': 123,
    'sensitive': True,
    'cc': [
        '...',
    ],
    'retention_policy': '...',
    'retention_action': '...',
    'external_reference_date': '...',
    'original_date': '...',
    'reason_delay': '...',
}
response = requests.post("https://api.openstudio.one/v1/protocol-registration", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/protocol-registration', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'box': '...',
    'subject': '...',
    'classification': '...',
    'correspondent_record_id': 123,
    'resp_dep': '...',
    'resp_user': '...',
    'posted_by_dep': '...',
    'routed_to_dep': '...',
    'routed_to_user': '...',
    'note': '...',
    'keywords': '...',
    'transmission_means': '...',
    'external_reference': '...',
    'visibility': 123,
    'sensitive': true,
    'cc': [
      '...',
    ],
    'retention_policy': '...',
    'retention_action': '...',
    'external_reference_date': '...',
    'original_date': '...',
    'reason_delay': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
id integer — Use this with GET /protocol-documents/{id}.
display_number string — The newly assigned protocol number.

Example response

{
    "success": true,
    "data": {
        "id": 9001,
        "display_number": "05674/2026"
    },
    "error": null
}

Reference data

GET /reference/protocol-mezzi

List the real "means of transmission" options for a Protocol registration

User key

Example request

curl -X GET "https://api.openstudio.one/v1/reference/protocol-mezzi" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/protocol-mezzi');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/reference/protocol-mezzi", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/reference/protocol-mezzi', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to reference/protocol-mezzi. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
mezzi array of objects — Every selectable transmission means.
↳var string — The value to send as a registration's q_mezzo.
↳label string — Human-readable label.

Example response

{
    "success": true,
    "data": {
        "mezzi": [
            {
                "var": "mail",
                "label": "Mail"
            },
            {
                "var": "pec",
                "label": "PEC"
            },
            {
                "var": "hand_delivered",
                "label": "Hand-delivered"
            }
        ]
    },
    "error": null
}

GET /reference/protocol-index-entries

List Entry Index templates for auto-filling a Protocol registration

User key

Example request

curl -X GET "https://api.openstudio.one/v1/reference/protocol-index-entries" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/protocol-index-entries');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/reference/protocol-index-entries", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/reference/protocol-index-entries', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to reference/protocol-index-entries. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
entries array of objects — Matching templates.
↳id integer — —
↳label string — —
↳subject string —
↳classification_var string Matches a protocol-classifications specific option's own var.
↳rpa_dep string —
↳rpa_user integer —
↳rpa_name string —
↳visibility integer — —
↳keywords string —
↳notes string —
↳mezzo string —
↳cc array of objects — —
↳dep string — —
↳user string — —
↳name string Resolved display name for user, when set.
↳whole_uor boolean — —
↳retention_policy string Mapped from the template's own configured retention period.
1_year
2_years
5_years
10_years
permanent
↳retention_action string —
migrate
delete

Example response

{
    "success": true,
    "data": {
        "entries": [
            {
                "id": 1,
                "label": "Standard invoice",
                "subject": "Invoice",
                "classification_var": "costs_outputs",
                "rpa_dep": "FIN",
                "rpa_user": 10000012,
                "rpa_name": "Maria Bianchi",
                "visibility": 0,
                "keywords": "invoice, billing",
                "notes": null,
                "mezzo": "pec",
                "cc": [],
                "retention_policy": "10_years",
                "retention_action": "migrate"
            }
        ]
    },
    "error": null
}

GET /reference/protocol-manageable-uors

List the UORs the caller can register a document "on behalf of"

User key

Example request

curl -X GET "https://api.openstudio.one/v1/reference/protocol-manageable-uors" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/protocol-manageable-uors');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/reference/protocol-manageable-uors", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/reference/protocol-manageable-uors', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to reference/protocol-manageable-uors. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
uors array of objects — —
↳code string — —
↳title string —
↳is_primary boolean — —
primary string —
has_storage_endpoint boolean — Whether the tenant has a real cold-storage endpoint configured — a retention policy asking to migrate there is silently coerced to delete-on-expiry when this is false.

Example response

{
    "success": true,
    "data": {
        "uors": [
            {
                "code": "ICT",
                "title": "IT & Systems",
                "is_primary": true
            }
        ],
        "primary": "ICT"
    },
    "error": null
}

GET /reference/protocol-structure-people

List who's assignable as RPA/CC within a given structure

User key
Query parameters (2)

Other

ParameterTypeRequiredNotes
?structurestringOptionalA real department acronym. Required.
?qstringOptionalOptional first/last-name filter.

Example request

curl -X GET "https://api.openstudio.one/v1/reference/protocol-structure-people?structure=...&q=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/protocol-structure-people?structure=...&q=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/reference/protocol-structure-people?structure=...&q=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/reference/protocol-structure-people?structure=...&q=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to reference/protocol-structure-people. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
structure object — —
people array of objects — —
↳user_id integer —
↳personal_code integer — —
↳first_name string — —
↳last_name string — —
↳photo_url string — —
↳structure_acronym string —
↳is_protocol_enabled boolean — —
↳is_head_of_unit boolean — —

Example response

{
    "success": true,
    "data": {
        "structure": {
            "acronym": "ICT",
            "title": "IT & Systems"
        },
        "people": [
            {
                "personal_code": 10000042,
                "first_name": "Mario",
                "last_name": "Rossi",
                "is_protocol_enabled": true,
                "is_head_of_unit": false
            }
        ]
    },
    "error": null
}

GET /reference/acl-structures

Live authorization directory for every structure (read-only)

User key
Query parameters (2)

Other

ParameterTypeRequiredNotes
?qstringOptionalDirectory mode only — filters by structure acronym/title.
?acronymstringOptionalSwitches to detail mode for one structure (or "_org_").

Example request

curl -X GET "https://api.openstudio.one/v1/reference/acl-structures?q=...&acronym=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/acl-structures?q=...&acronym=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/reference/acl-structures?q=...&acronym=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/reference/acl-structures?q=...&acronym=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to reference/acl-structures. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
type string — —

Example response

{
    "success": true,
    "data": {
        "areas": [
            {
                "acronym": "IT",
                "title": "Information Technology",
                "units": [
                    {
                        "acronym": "ICT",
                        "status": "active",
                        "management_count": 2,
                        "view_count": 5
                    }
                ]
            }
        ]
    },
    "error": null
}

GET /reference/acl-profiles

Permission profiles (roles) and their real grants (read-only)

User key
Query parameters (1)

Other

ParameterTypeRequiredNotes
?codestringOptionalSwitches to detail mode for one profile.

Example request

curl -X GET "https://api.openstudio.one/v1/reference/acl-profiles?code=..." \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/acl-profiles?code=...');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/reference/acl-profiles?code=...", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/reference/acl-profiles?code=...', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to reference/acl-profiles. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
type string — —

Example response

{
    "success": true,
    "data": {
        "profiles": [
            {
                "code": "OP1",
                "name": "Operator",
                "description": "Standard protocol operator."
            }
        ]
    },
    "error": null
}

Digital Signature

Certificates

GET /digisign/certificates

Your digital-signature certificate status and history

User key

Example request

curl -X GET "https://api.openstudio.one/v1/digisign/certificates" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/digisign/certificates');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/digisign/certificates", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/digisign/certificates', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to digisign/certificates. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
certificates array of objects — —
↳id integer — —
↳status_label string — —
Request Sent
Active
Expired
Revoked
Cancelled
↳valid_from string —
↳valid_to string —
↳common_name string —
has_active_certificate boolean — —

Example response

{
    "success": true,
    "data": {
        "certificates": [
            {
                "id": 12,
                "status_label": "Active",
                "valid_from": "2026-01-10 00:00:00",
                "valid_to": "2027-01-10 00:00:00",
                "common_name": "Nicol\u00f2 Chierichetti"
            }
        ],
        "has_active_certificate": true
    },
    "error": null
}

Signed documents

GET /digisign/documents

Your signed-documents repository

User key

Example request

curl -X GET "https://api.openstudio.one/v1/digisign/documents" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/digisign/documents');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/digisign/documents", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/digisign/documents', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to digisign/documents. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
documents array of objects — —
↳id integer — —
↳signed_name string — —
↳date_signed string — —
↳download_id integer — Use with GET /digisign/documents/{id}/download — real, authenticated download, never a raw public URL.

Example response

{
    "success": true,
    "data": {
        "documents": [
            {
                "id": 7,
                "signed_name": "SIGNED_report.pdf",
                "date_signed": "2026-08-20 14:03:00",
                "download_id": 7
            }
        ]
    },
    "error": null
}

DELETE /digisign/documents

Remove a signed document from your repository (soft delete)

User key

Example request

curl -X DELETE "https://api.openstudio.one/v1/digisign/documents" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/digisign/documents');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.delete("https://api.openstudio.one/v1/digisign/documents", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/digisign/documents', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

GET /digisign/documents/{document_id}/download

Download a signed PDF (real, authenticated)

User key

Example request

curl -X GET "https://api.openstudio.one/v1/digisign/documents/{document_id}/download" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/digisign/documents/{document_id}/download');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/digisign/documents/{document_id}/download", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/digisign/documents/{document_id}/download', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to digisign/documents/{document_id}/download. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
type string — —
format string — —
description string — —

Example response

{
    "success": true,
    "data": {},
    "error": null
}

Signing verification

POST /digisign/otp

Request/resend/verify a signing OTP

User key

Request body

FieldTypeFlagsRequiredNotes
filenames array — Optional request/resend only — cosmetic context for the OTP email (what's being signed).
otp_code string — Optional verify only — the 6-digit code.

Example request

curl -X POST "https://api.openstudio.one/v1/digisign/otp" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filenames":["..."],"otp_code":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/digisign/otp');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'filenames' => [
        '0' => '...',
    ],
    'otp_code' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'filenames': [
        '...',
    ],
    'otp_code': '...',
}
response = requests.post("https://api.openstudio.one/v1/digisign/otp", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/digisign/otp', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'filenames': [
      '...',
    ],
    'otp_code': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

Sign

POST /digisign/sign

Digitally sign one or more PDF files

User key

Request body

FieldTypeFlagsRequiredNotes
certificate_id integer — Required One of your own active certificates — from GET /digisign/certificates.
location string — Optional —
reason string — Optional —
files array — Required Array of {filename, file_base64} — a data: URI or bare base64 PDF, same convention as every other file-upload field in this API.

Example request

curl -X POST "https://api.openstudio.one/v1/digisign/sign" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"certificate_id":123,"location":"...","reason":"...","files":["..."]}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/digisign/sign');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'certificate_id' => 123,
    'location' => '...',
    'reason' => '...',
    'files' => [
        '0' => '...',
    ],
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'certificate_id': 123,
    'location': '...',
    'reason': '...',
    'files': [
        '...',
    ],
}
response = requests.post("https://api.openstudio.one/v1/digisign/sign", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/digisign/sign', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'certificate_id': 123,
    'location': '...',
    'reason': '...',
    'files': [
      '...',
    ],
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
signed array of objects — —
↳name string — —
↳download_id integer — Use with GET /digisign/documents/{id}/download.
failed array of objects — —
↳name string — —
↳error string — —

Example response

{
    "success": true,
    "data": {
        "signed": [
            {
                "name": "SIGNED_contract.pdf",
                "download_id": 8
            }
        ],
        "failed": []
    },
    "error": null
}

Verify

POST /digisign/verify

Verify a signed PDF's own signature(s)

User key

Request body

FieldTypeFlagsRequiredNotes
filename string — Optional —
file_base64 string — Required A data: URI or bare base64 PDF.

Example request

curl -X POST "https://api.openstudio.one/v1/digisign/verify" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename":"...","file_base64":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/digisign/verify');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'filename' => '...',
    'file_base64' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'filename': '...',
    'file_base64': '...',
}
response = requests.post("https://api.openstudio.one/v1/digisign/verify", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/digisign/verify', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'filename': '...',
    'file_base64': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
signature_count integer — —
signers array of objects — —
↳signer_name string —
↳is_openstudio_member boolean — —
↳revocation_state string — —
active
revoked
valid
unknown
↳authority_verified boolean — —

Example response

{
    "success": true,
    "data": {
        "signature_count": 1,
        "signers": [
            {
                "signer_name": "Nicol\u00f2 Chierichetti",
                "is_openstudio_member": true,
                "revocation_state": "active",
                "authority_verified": true
            }
        ]
    },
    "error": null
}

Intranet

GET /intranet/home

Intranet home — greeting, latest news, new colleagues

User key

Example request

curl -X GET "https://api.openstudio.one/v1/intranet/home" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/home');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/intranet/home", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/home', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to intranet/home. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
news array of objects — Up to 3 latest news cards.
↳id integer — —
↳title string — —
↳summary string —
↳category string — —
↳is_pinned boolean — —
↳has_poll boolean — —
↳has_read boolean — Whether the caller has already opened this article.
↳unique_readers integer —
↳reply_count integer — —
↳created_at string — —
new_colleagues array of objects — Recently-joined people, matching the web widget's own recency window.
↳user_id integer — —
↳display_name string — —
↳avatar_url string —
↳structure string —

Example response

{
    "success": true,
    "data": {
        "news": [
            {
                "id": 12,
                "title": "New badge system",
                "summary": "Rolling out next week.",
                "category": "Announcements",
                "is_pinned": true,
                "has_poll": false,
                "has_read": false,
                "unique_readers": 34,
                "reply_count": 5,
                "created_at": "2026-08-20 09:00:00"
            }
        ],
        "new_colleagues": [
            {
                "user_id": 501,
                "display_name": "Priya Shah",
                "avatar_url": null,
                "structure": "Finance"
            }
        ]
    },
    "error": null
}

GET /intranet/news

List/search intranet news

User key
Query parameters (3)

Pagination

ParameterTypeRequiredNotes
?limitintegerOptionalDefaults to 9 (feed) or 20 (archive).

Other

ParameterTypeRequiredNotes
?qstringOptionalSubstring match on title/summary/content.
?archivebooleanOptionalWidens the date window and page size to the full archive, instead of just the latest items.

Example request

curl -X GET "https://api.openstudio.one/v1/intranet/news?q=...&archive=true&limit=123" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/news?q=...&archive=true&limit=123');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/intranet/news?q=...&archive=true&limit=123", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/news?q=...&archive=true&limit=123', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to intranet/news. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
items array of objects — —
↳id integer — —
↳display_id integer —
↳title string — —
↳headline string —
↳summary string —
↳category string — —
↳is_pinned boolean — —
↳author_name string — —
↳views integer — —
↳reply_count integer — —
↳created_at string — —

Example response

{
    "success": true,
    "data": {
        "items": [
            {
                "id": 12,
                "display_id": 4,
                "title": "New badge system",
                "headline": null,
                "summary": "Rolling out next week.",
                "category": "Announcements",
                "is_pinned": true,
                "author_name": "HR Team",
                "views": 120,
                "reply_count": 5,
                "created_at": "2026-08-20 09:00:00"
            }
        ]
    },
    "error": null
}

GET /intranet/news/{id}

Get one news article, with reactions/poll/comments/related updates

User key

Example request

curl -X GET "https://api.openstudio.one/v1/intranet/news/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/news/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.get("https://api.openstudio.one/v1/intranet/news/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/news/{id}', {
  method: 'GET',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

ⓘRuns a real request from your browser directly to intranet/news/{id}. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
id integer — —
title string — —
content string — Rich-text HTML, rendered via the same FormattedHtml component ticket comments use.
hashtags array of strings — —
author_name string — —
author_structure string —
reactions object — —
↳totals object — Per-reaction-type counts, e.g. {"like": 4, "love": 1}.
↳total integer — —
↳my_reaction string —
poll object Absent when the article has no poll.
comments array — —
related array — Other recent news items, for the "Related updates" section.
allow_comments boolean — —
can_post_comments boolean — —

Example response

{
    "success": true,
    "data": {
        "id": 12,
        "title": "New badge system",
        "content": "<p>We are rolling out a new badge system next week.</p>",
        "hashtags": [
            "hr",
            "facilities"
        ],
        "author_name": "HR Team",
        "author_structure": "Human Resources",
        "reactions": {
            "totals": {
                "like": 4
            },
            "total": 4,
            "my_reaction": null
        },
        "poll": null,
        "comments": [],
        "related": [],
        "allow_comments": true,
        "can_post_comments": true
    },
    "error": null
}

POST /intranet/news/{id}/reaction

Set or clear the caller's reaction on a news article

User key

Request body

FieldTypeFlagsRequiredNotes
type string — Required One of like/love/haha/wow/sad/angry, or an empty string to remove the caller's reaction.

Example request

curl -X POST "https://api.openstudio.one/v1/intranet/news/{id}/reaction" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/news/{id}/reaction');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'type' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'type': '...',
}
response = requests.post("https://api.openstudio.one/v1/intranet/news/{id}/reaction", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/news/{id}/reaction', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'type': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /intranet/news/{id}/poll-vote

Vote (or cancel a vote) on a news article's poll

User key

Request body

FieldTypeFlagsRequiredNotes
option_index integer — Required A poll option's 0-based index, or -1 to cancel the caller's existing vote (only when the poll allows cancellation).

Example request

curl -X POST "https://api.openstudio.one/v1/intranet/news/{id}/poll-vote" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"option_index":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/news/{id}/poll-vote');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'option_index' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'option_index': 123,
}
response = requests.post("https://api.openstudio.one/v1/intranet/news/{id}/poll-vote", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/news/{id}/poll-vote', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'option_index': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

POST /intranet/news/{id}/comments

Post a comment (or a flat reply) on a news article

User key

Request body

FieldTypeFlagsRequiredNotes
content string — Required —
parent_id integer — Optional An existing top-level comment's id, to mark this as a reply to it.

Example request

curl -X POST "https://api.openstudio.one/v1/intranet/news/{id}/comments" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"...","parent_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/news/{id}/comments');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'content' => '...',
    'parent_id' => 123,
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'content': '...',
    'parent_id': 123,
}
response = requests.post("https://api.openstudio.one/v1/intranet/news/{id}/comments", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/news/{id}/comments', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'content': '...',
    'parent_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
id integer — —

Example response

{
    "success": true,
    "data": {
        "id": 88
    },
    "error": null
}

PATCH /intranet/comments/{id}

Edit a comment the caller authored (or any comment, for a moderator)

User key

Request body

FieldTypeFlagsRequiredNotes
content string — Required —

Example request

curl -X PATCH "https://api.openstudio.one/v1/intranet/comments/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"..."}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/comments/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'content' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

body = {
    'content': '...',
}
response = requests.patch("https://api.openstudio.one/v1/intranet/comments/{id}", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/comments/{id}', {
  method: 'PATCH',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'content': '...',
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
success boolean — —

Example response

{
    "success": true,
    "data": {
        "success": true
    },
    "error": null
}

DELETE /intranet/comments/{id}

Delete a comment the caller authored (or any comment, for a moderator)

User key

Example request

curl -X DELETE "https://api.openstudio.one/v1/intranet/comments/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/intranet/comments/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);

$response = curl_exec($ch);
$data = json_decode($response, true);
import requests

headers = {
    "X-Api-User-Key": "YOUR_USER_KEY",
}

response = requests.delete("https://api.openstudio.one/v1/intranet/comments/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/intranet/comments/{id}', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes

Example response

{
    "success": true,
    "data": {},
    "error": null
}
ESC