This example demonstrates how to send a fax using the sipgate REST API.
For further information regarding the sipgate REST API please visit https://api.sipgate.com/v2/doc
- JDK 8
Create the .env
by copying the .env.example
and set the values according to the comment above each variable.
The token must have the sessions:fax:write
and history:read
scopes.
For more information about personal access tokens visit our website.
The FAXLINE_ID
uniquely identifies the extension from which you wish to send your fax. Further explanation is given in the section Fax Extensions.
Although the API accepts various formats of fax numbers, the recommended format for the RECIPIENT
is the E.164 standard.
PDF_FILE_PATH
expects an either relative or absolute file path to your desired PDF file to be sent.
Run the application:
./gradlew run
Note: On Windows use gradlew.bat
instead of ./gradlew
.
In SendFax.main()
we check that the user provides the recipient phone number and an existing PDF:
private static final String FAX_NUMBER_PATTERN = "\\+?[0-9]+";
public static void main(String[] args) {
...
if (!recipient.matches(FAX_NUMBER_PATTERN)) {
System.err.println("Invalid recipient faxRequest number");
return;
}
Path pdfFilepath = Paths.get(pdfPath);
if (!Files.exists(pdfFilepath)) {
System.err.println(String.format("File does not exist: %s", pdfFilepath));
return;
}
String encodedPdf;
try {
encodedPdf = encodePdf(pdfFilepath);
} catch (IOException | IllegalArgumentException e) {
System.err.println(String.format("Failed to encode file %s: %s", pdfFilepath, e.getMessage()));
return;
}
...
}
After that we ensure that the mime-type of the file is application/pdf
, read the file contents, and encode it with Base64
private static String encodePdf(Path pdfFilepath) throws IOException, IllegalArgumentException {
String contentType = Files.probeContentType(pdfFilepath);
if (contentType == null || !contentType.equals("application/pdf")) {
throw new IllegalArgumentException("Not a valid pdf file");
}
byte[] pdfFileContent = Files.readAllBytes(pdfFilepath);
byte[] encodedPdfFileContent = Base64.getEncoder().encode(pdfFileContent);
return new String(encodedPdfFileContent);
}
Then we construct a FaxRequest
object:
String filename = pdfFilepath.getFileName().toString();
Fax fax = new Fax(faxlineId, recipient, filename, encodedPdf);
We pass Unirest a ResponseMapper
for mapping responses in JSON format to Java objects:
Unirest.setObjectMapper(new ResponseMapper());
After that, we call our sendFax
method with the FaxRequest
object as a parameter. The return value is the sessionId
, which we will later use to track the sending status.
String sessionId;
try {
sessionId = sendFax(faxRequest);
} catch (UnirestException e) {
System.err.println(String.format("Fax request failed: %s", e.getMessage()));
return;
}
In the sendFax
method, we define the headers and the request body, which contains the FaxRequest object with faxlineId
, recipient
, filename
, and base64Content
.
We use the Unirest library for request generation and execution. The post()
method takes as argument the request URL. The headers, authorization header, and request body are set by the header()
, basicAuth()
and body()
method, respectively.
The request URL consists of the base URL defined above and the endpoint /sessions/fax
.
The basicAuth()
method from the Unirest package takes credentials and generates the required Basic Auth header (for more information on Basic Auth see our code example).
private static String sendFax(FaxRequest faxRequest) throws UnirestException {
RequestBodyEntity response = Unirest.post(baseUrl + "/sessions/fax")
.basicAuth(tokenId, token)
.header("Content-Type", "application/json")
.body(faxRequest);
Next we check if the httpStatus
is 200 indicating that the request to send the fax was received successfully.
int httpStatus = response.asString()
.getStatus();
if (httpStatus != 200) {
throw new UnirestException(String.format("Server responded with error code %s", httpStatus));
}
Note: Although the API returns the status 200 it does not mean that the fax was sent, only that it has been queued for sending.
If the request was successful, we map the response to a FaxResponse
object and return its sessionId
:
FaxResponse faxResponseBody = response.asObject(FaxResponse.class)
.getBody();
return faxResponseBody.sessionId;
To check the status of the fax, we update the faxStatusType
in 5 second intervals using our sessionId
. This process repeats until the faxStatusType
is either "SENT"
or "FAILED"
.
String faxStatusType = "";
do {
try {
faxStatusType = pollSendStatus(sessionId);
System.out.println(faxStatusType);
Thread.sleep(5 * 1000);
} catch (InterruptedException | UnirestException e) {
e.printStackTrace();
return;
}
} while (!faxStatusType.equals("FAILED") && !faxStatusType.equals("SENT"));
In the pollSendStatus
function we make a GET request to the /history/{sessionId}
endpoint which yields the history entry that corresponds to our fax.
In this case we are only interested in the faxStatusType
.
private static String pollSendStatus(String sessionId) throws UnirestException {
JsonNode historyEntryResponse = Unirest.get(baseUrl + "/history/" + sessionId)
.basicAuth(tokenId, token)
.asJson()
.getBody();
return historyEntryResponse.getObject().getString("faxStatusType");
}
The faxStatusType
can be one of the following values:
PENDING
: The fax was added to the queue for sending, but the sending process has not started yetSENDING
: The fax is currently being sentFAILED
: The fax could not be sentSENT
: The fax was sent successfullySCHEDULED
: The fax is scheduled for sending at the specified timestamp (it is notPENDING
because it is not waiting in the queue of faxes to be sent yet)
A fax extension consists of the letter f
followed by a number (e.g. f0
). The sipgate API uses the concept of fax extensions to identify devices within your account that are enabled to send fax. In this context the term device does not necessarily refer to a hardware fax but rather a virtual representation.
You can find out what your extension is as follows:
- Log into your sipgate account
- Use the sidebar to navigate to the Routing (Telefonie) tab
- Click on any Fax device in your routing table
- Select any option (gear icon) to open the corresponding menu
- The URL of the page should have the form
https://app.sipgate.com/w0/routing/dialog/{option}/{faxlineId}
where{faxlineId}
is your Fax extension.
Possible reasons are:
- PDF file not encoded correctly in base64
- PDF file with text fields or forms are not supported
- PDF file is corrupted
reason | errorcode |
---|---|
bad request (e.g. request body fields are empty or only contain spaces, timestamp is invalid etc.) | 400 |
tokenId and/or token are wrong | 401 |
your account balance is insufficient | 402 |
no permission to use specified Fax extension (e.g. Fax feature not booked or user password must be reset in web app) | 403 |
wrong REST API endpoint | 404 |
wrong request method | 405 |
invalid recipient fax number | 407 |
wrong or missing Content-Type header with application/json |
415 |
internal server error or unhandled bad request | 500 |
Please let us know how we can improve this example. If you have a specific feature request or found a bug, please use Issues or fork this repository and send a pull request with your improvements.
This project is licensed under The Unlicense (see LICENSE file).
This code uses the following external libraries
-
Unirest:
- Licensed under the MIT License
- Website: http://unirest.io/java.html
-
Jackson:
- Licensed under the Apache-2.0
- Website: https://github.com/FasterXML/jackson