Reference
Migrating from another system
Mapping common online office suite concepts to the O3O API, differences to watch and the migration steps.
On this page
Online office suites share many concepts: an editor configuration, a document version identifier, save callbacks, a conversion service. This page maps those concepts to the O3O API so a move to O3O has a clear path. The field names, signing scheme and behaviour below are O3O's own.
Concept map#
| Common concept | O3O | Notes |
|---|---|---|
| Embedded editor created from a configuration object in the browser | new O3O.Editor(id, config), loaded from /o3o/api.js | api.js derives the server address from its own script tag. |
| URL the server downloads the source file from | document.url | Downloaded by the O3O server, not the browser; subject to SSRF rules. |
| Document version identifier that groups co-editors | document.key | Matches ^[A-Za-z0-9._-]{1,128}$; use a new key after the closed callback. |
| File type and display name | document.fileType, document.title | 12 accepted extensions. |
| Edit or view-only mode | editor.mode: edit / view | view does not count as a connection. |
| Current user and interface language | editor.user.id, editor.user.name, editor.lang | |
| URL notified when the document is saved | editor.callbackUrl | See Callbacks and webhooks. |
| Configuration signed as a JWT | token HS256, the payload is the config itself | No wrapper object inside the payload. |
| Status in the save callback | status: saved / closed | With the final, autosave, modifiedByUser flags; no numeric status codes. |
| Callback reply body in a prescribed shape | Any 2xx status | The reply body is ignored. |
| Callback authentication | X-O3O-Signature, X-O3O-Timestamp | HMAC SHA-256 |
| Downloading the saved file | Signed url in the callback and in onSaved | Valid for O3O_EMBED_RETAIN_HOURS hours. |
| Browser-side events | onReady, onDocumentLoaded, onModified, onSaved, onClose, onLimitReached, onError | |
| Editor object methods | save(), close(), destroy(), setReadOnly(), getInfo() | |
| Interface customisation | ui | Size, toolbar style, close button, print, export, copy, user list. Logo, colours, dark theme: coming soon. |
| Format conversion service with an asynchronous mode | POST /v1/convert → GET /v1/jobs/{id} → GET /v1/files/{id} | Source is file (multipart) or url (JSON). |
| Building documents without a browser | POST /v1/build + o3oscript | Scripts are declarative JSON, not executable code. |
| Mail merge, template filling | POST /v1/template/render | {{field}} and table row loops; enterprise edition only. |
| Connecting a file store over WOPI | /hosting/discovery, CheckFileInfo, GetFile, PutFile | Nextcloud through the richdocuments app. |
| Per-connection licensing | 1 connection = 1 concurrent editing session | See How connections are counted. |
| Health checks | GET /o3o/healthz, GET /v1/status |
Differences to watch#
- Callbacks have only two states,
savedandclosed, and carry a signed download URL. Download the file before the URL expires. - A callback receiver only needs to answer 2xx. O3O tries 3 times (first try, after 10 seconds, after 60 seconds), so the receiver must be idempotent.
- After the
closedcallback, the next opening must use a newdocument.key. - Only HS256 JWTs are accepted; any other algorithm,
noneincluded, is rejected. - Conversion only works within one document family (text, spreadsheet, presentation); synchronous mode returns the file directly.
- Document build scripts are declarative JSON following the o3oscript schema; no client code is executed.
- Read-only sessions do not count; reaching the cap disconnects nobody, and new sessions open read-only.
Coming soon
A /compat/* compatibility layer for running existing integration code unchanged.
Migration steps#
Inventory
List where the editor is opened, the callback receivers, the conversion calls and the document build scripts in the current system.Set up a test machine
Run the Docker bundle following Self-hosting and try the/o3o/demopage.Map the configuration
Build theO3O.Editorconfig from the table above; sign it as a JWT on your server.Rewrite the callback receiver
Verify the signature, be idempotent, answer 2xx at once, downloadurlin the background.Move document processing calls
Conversions to/v1/convert, document building to o3oscript, mail merge to/v1/template/render.Test the limits
Switch over gradually
Run both systems side by side, move one module at a time; compare saved files before turning the old system off.
// Browser, after loading http://localhost:8080/o3o/api.js
const editor = new O3O.Editor("o3o-editor", {
document: {
url: "https://example.com/files/hop-dong.docx", // the O3O server downloads this file
title: "Hợp đồng mẫu.docx",
fileType: "docx",
key: "hopdong-42-v7" // a new key for every content version
},
editor: {
mode: "edit",
lang: "vi",
user: { id: "u-1001", name: "Nguyễn Văn A" },
callbackUrl: "https://example.com/o3o/callback" // receives saved and closed
},
token: tokenFromServer, // JWT signed by your server
events: {
onSaved: (e) => console.log(e.version, e.url),
onLimitReached: (e) => console.warn(e.message),
onError: (e) => console.error(e.code, e.message)
}
});# Synchronous conversion: returns the PDF directly
curl -s http://localhost:8080/v1/convert \
-H "Authorization: Bearer O3O_DEMO_KEY" \
-F file=@bao-cao.docx -F to=pdf -o bao-cao.pdf
# Asynchronous: get a job, poll it, download the file
curl -s http://localhost:8080/v1/convert \
-H "Authorization: Bearer O3O_DEMO_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/files/bao-cao.docx", "to": "pdf", "async": true}'
curl -s http://localhost:8080/v1/jobs/job_4f1c2a9b0d3e5f6a7b8c9d0e -H "Authorization: Bearer O3O_DEMO_KEY"
curl -s http://localhost:8080/v1/files/file_9a8b7c6d5e4f3a2b1c0d9e8f -H "Authorization: Bearer O3O_DEMO_KEY" -o bao-cao.pdf