Skip to main content

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 accesses fileUrl and callback callback, either header or cookie (optional)
  • tokenValue: Authentication value matching tokenType (Authorization value when tokenType is header; format like k1=v1;k2=v2 when cookie) (optional)

For related basic concepts, see:

2. End-to-End Example

The call flow is:

  1. Submit a conversion task (/convert)
  2. Get task result by callback or active polling (/queryTaskStatus)
  3. 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.