To demonstrate how to send an Fax, we queried the /sessions/fax
endpoint of the sipgate REST API.
For further information regarding the sipgate REST API please visit https://api.sipgate.com/v2/doc
- python3
- pip3
Install dependencies:
$ pip3 install -r requirements.txt
In the .env file located in the project root directory insert YOUR_SIPGATE_TOKEN_ID
, YOUR_SIPGATE_TOKEN
, and YOUR_SIPGATE_FAXLINE_EXTENSION
:
...
TOKEN_ID="YOUR_SIPGATE_TOKEN_ID",
TOKEN="YOUR_SIPGATE_TOKEN",
FAXLINE_ID="YOUR_SIPGATE_FAXLINE_EXTENSION",
...
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:
python3 send_fax.py
In our main script, the send_fax.py, we check that the user provides the recipient phone number and a PDF, we also ensure that the mime-type of the file is application/pdf
.
def validate_env_values():
if not re.match(FAX_NUMBER_PATTERN, RECIPIENT):
sys.stderr.write('Invalid recipient fax number.')
exit(2)
if not os.path.isfile(PDF_FILE_PATH):
sys.stderr.write('File not found: {}'.format(PDF_FILE_PATH))
exit(3)
mimetype, encoding = mimetypes.guess_type(PDF_FILE_PATH)
if not mimetype == 'application/pdf':
sys.stderr.write('Invalid file type: {}'.format(mimetype))
exit(4)
After that we read the file contents and encode it with Base64.
with open(PDF_FILE_PATH, 'rb') as pdf_file:
encoded_pdf = base64.b64encode(pdf_file.read())
After that we call our send_fax
function and pass the encoded_pdf, pdf_filename, recipient and authorization as arguments.
session_id = send_fax(encoded_pdf, pdf_filename, RECIPIENT, authorization)
In the send_fax
function, we define the headers and the request body, which contains the faxlineId
, recipient
, filename
, and base64Content
.
headers = {
'Content-Type': 'application/json'
}
request_body = {
'faxlineId': config['faxlineId'],
'recipient': recipient,
'filename': pdf_filename,
'base64Content': encoded_pdf
}
We use the python package 'requests' for request generation and execution. The post
function takes as arguments the request URL, headers, an authorization header, and the request body. The request URL consists of the base URL defined above and the endpoint /sessions/fax
. The function HTTPBasicAuth
from the 'requests' package takes credentials and generates the required Basic Auth header (for more information on Basic Auth see our code example).
def send_fax(encoded_pdf, pdf_filename, recipient, authorization):
url = BASE_URL + '/sessions/fax'
headers = {
'Content-Type': 'application/json'
}
request_body = {
'faxlineId': FAXLINE_ID,
'recipient': recipient,
'filename': pdf_filename,
'base64Content': encoded_pdf.decode("utf-8")
}
response = requests.post(url,
headers=headers,
json=request_body,
auth=authorization)
status_code = response.status_code
if not status_code == 200:
sys.stderr.write('An error occurred while communicating with the sipgate REST API: ')
sys.stderr.write('status code {} (see README for details)'.format(status_code))
exit(5)
response_body = response.json()
session_id = response_body['sessionId']
return session_id
Next we check if the status of our response
is 200, meaning that the request to send the fax was successfully received.
Note: Although the Api returns the status 200 it does not mean that the fax was sent. It was only added to a queue for sending.
To check the status of the fax we use the session_id
, returned by the send_fax
function, and pass it to the poll_send_status
function. In this example we use time.sleep
to check the status of the fax every five seconds.
send_status = 'STARTING'
while send_status in ('STARTING', 'PENDING', 'SENDING'):
print(send_status)
send_status = poll_send_status(session_id, authorization)
time.sleep(5)
In the poll_send_status
function we use requests again to query the /history/{sessionId}
endpoint to get the history entry for our fax. In this case we are only interested in the faxStatusType
.
def poll_send_status(session_id, authorization):
url = '{}/history/{}'.format(BASE_URL, session_id)
headers = {
'Content-Type': 'application/json'
}
response = requests.get(url,
headers=headers,
auth=authorization)
response_body = response.json()
return response_body['faxStatusType']
The faxStatusType
can contain 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 corrupt
reason | errorcode |
---|---|
bad request (e.g. request body fields are empty or only contain spaces, timestamp is invalid etc.) | 400 |
TOKEN_ID 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
- requests:
- Licensed under the Apache License 2.0
- Website: http://docs.python-requests.org/en/master/
- python-dotenv