Quick Start
1. Prerequisites
Before calling Open API, complete the management console configuration first. See Preparation Before Calling Open API.
Prepare the following information (used in later examples):
repoId: Third-party application ID (must match the management console configuration)openApiSecret: Open API secret key (used to calculate authentication headers, must match the console configuration, and is defined by the third party)fileUrl: URL where your business system can download the source file (hostname must match the console configuration)callback: Callback URL after task completion (hostname must also match) (optional)tokenType: Authentication type used when the platform accessesfileUrland callbackcallback, eitherheaderorcookie(optional)tokenValue: Authentication value matchingtokenType(Authorizationvalue whentokenTypeisheader; format likek1=v1;k2=v2whencookie) (optional)
For related basic concepts, see:
2. End-to-End Example
The call flow is:
- Submit a conversion task (
/convert) - Get task result by callback or active polling (
/queryTaskStatus) - Download result file (
/download)
The example below uses "Word to PDF" and active polling.
API docs:
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.math.BigInteger;
import java.util.UUID;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class OpenApiFullFlowDemo {
private static final String REPO_ID = "yourRepoId";
private static final String SECRET = "yourOpenApiSecret";
private static final String HOST = "http://{zofficehost}:8001";
private static final ObjectMapper MAPPER = new ObjectMapper();
public static void main(String[] args) throws Exception {
try (CloseableHttpClient client = HttpClients.createDefault()) {
// Step 1: Submit conversion task (/convert) and get taskId
// callback cannot be empty. If callback is not implemented, you can pass a fake URL,
// but the host must still match the management console configuration.
// Fill tokenType/tokenValue as needed. The platform includes tokenValue when calling file download (fileUrl) and callback notification (callback).
// tokenType=header means tokenValue is sent in the Authorization header.
// tokenType=cookie means tokenValue is sent in Cookie. In this case tokenValue should look like `token=xxx`.
String convertBody = "{"
+ "\"fileUrl\":\"https://your-host/files/demo.docx\","
+ "\"filename\":\"demo.docx\","
+ "\"targetFilename\":\"demo.pdf\","
+ "\"callback\":\"https://your-host/openapi/callback\","
+ "\"tokenType\":\"header\","
+ "\"tokenValue\":\"Bearer xxx\""
+ "}";
String convertResp = new String(
execute(client, "POST", "/docs/publicapi/v1/convert", convertBody),
StandardCharsets.UTF_8
);
System.out.println("convert response: " + convertResp);
String taskId = readField(convertResp, "taskId");
if (taskId == null || taskId.length() == 0) {
throw new IllegalStateException("taskId was not found in convert response");
}
// Step 2: Poll task status (/queryTaskStatus) until success and get contentId
String contentId = null;
for (int i = 0; i < 60; i++) { // poll at most 60 times
String queryPath = "/docs/publicapi/v1/queryTaskStatus?taskId=" + taskId;
String queryResp = new String(
execute(client, "GET", queryPath, null),
StandardCharsets.UTF_8
);
System.out.println("query response: " + queryResp);
String code = readField(queryResp, "code");
if ("TaskSuccessNotify".equals(code) || "ConvertSuccessNotify".equals(code)) {
contentId = readField(queryResp, "detail.contentId");
break;
}
if ("TaskFailNotify".equals(code) || "ConvertFailNotify".equals(code)) {
throw new IllegalStateException("task failed: " + queryResp);
}
Thread.sleep(1000L); // query every second
}
if (contentId == null || contentId.length() == 0) {
throw new IllegalStateException("task did not finish in time, no contentId returned");
}
// Step 3: Download result file (/download) and save locally
String downloadPath = "/docs/publicapi/v1/download?taskId=" + taskId + "&contentId=" + contentId;
byte[] fileBytes = execute(client, "GET", downloadPath, null);
Files.write(Paths.get("result.pdf"), fileBytes);
System.out.println("download success: result.pdf");
}
}
// Generic request executor:
// - If body is not empty, send as JSON and append @@body to signature seed.
// - If body is empty, send no request body and do not append @@body.
private static byte[] execute(CloseableHttpClient client, String method, String path, String body) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis());
String nonce = UUID.randomUUID().toString();
String authorization = buildAuthorization(timestamp, nonce, body);
RequestBuilder builder = RequestBuilder.create(method)
.setUri(HOST + path)
.setHeader("zOffice-auth-type", "s2s_MD5_sig")
.setHeader("zOffice-message-nonce", nonce)
.setHeader("timeStamp", timestamp)
.setHeader("Authorization", authorization);
if (body != null && !body.isEmpty()) {
builder.setHeader("Content-Type", "application/json");
builder.setEntity(new StringEntity(body, ContentType.APPLICATION_JSON));
}
HttpUriRequest request = builder.build();
try (CloseableHttpResponse response = client.execute(request)) {
return EntityUtils.toByteArray(response.getEntity());
}
}
// Read field by dotted path using Jackson, e.g. code, detail.contentId
private static String readField(String json, String path) throws Exception {
JsonNode root = MAPPER.readTree(json);
JsonNode current = root;
String[] segments = path.split("\\.");
for (String segment : segments) {
current = current.path(segment);
if (current.isMissingNode() || current.isNull()) {
return null;
}
}
return current.asText();
}
private static String buildAuthorization(String timestamp, String nonce, String body) throws Exception {
String seed = SECRET + "@@" + timestamp + "@@" + nonce;
if (body != null && !body.isEmpty()) {
seed += "@@" + body;
}
String sign = md5Hex(seed);
return REPO_ID + ":publicApi:" + sign;
}
private static String md5Hex(String input) throws Exception {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(input.getBytes(StandardCharsets.UTF_8));
return String.format("%032x", new BigInteger(1, md5.digest()));
}
}
After completing the steps above, you can run the basic Open API call flow end to end. For more capabilities, continue with the APIs for content processing, merge/split, edit protection, and more in API List.