NAV
cURL PHP Ruby Python

Introduction

Welcome to the Mifiel API! We at Mifiel provide a simple and robust RESTful API enabling any service or company operating in Mexico to integrate electronic signatures (using the FIEL) into their workflow.

Through Mifiel’s API, you can easily manage documents and certificates within your Mifiel account.

We have language bindings in Shell, PHP, Ruby and Python! You can view code examples on the right (switch between different programming languages using the tabs on top).

API Versions

All API calls are versioned, and the current Mifiel API is v1.0. We will never introduce any breaking changes within any version, but may add new, non-breaking features and enhancements from time to time.

Sandbox enviroment

For your convenience Mifiel offers a Sandbox environment where you can confidently test your code.

To start using the API in the Sandbox environment you need to first create an account at sandbox.mifiel.com.

Once you have an account you will need an APP_ID and an APP_SECRET which you can generate in sandbox.mifiel.com/access_tokens.

Just change the www.mifiel.com for sandbox.mifiel.com in every endpoint that you use.

Production enviroment

To start using the API in the Production environment you need to first create an account at mifiel.com.

Once you have an account you will need an APP_ID and a APP_SECRET which you can generate in mifiel.com/access_tokens.

Mifiel-supported SDKs

We currently suppport Ruby, PHP and Python but are working on adding more languages.

Ruby

# Configure Mifiel gem
Mifiel.config do |config|
  config.app_id = '<APP_ID>'
  config.app_secret = '<APP_SECRET>'
end

Add this line to your application’s Gemfile:

gem 'mifiel'

Then execute:

$ bundle

Or install it yourself as:

$ gem install mifiel

You can find the repo at github.com/Mifiel/ruby-api-client.

PHP

<?php
// include composer autoload
require 'vendor/autoload.php';

// import Mifiel Client Class
use Mifiel\ApiClient as Mifiel;

// Configure Mifiel Library
Mifiel::setTokens('APP_ID', 'APP_SECRET');
?>

The best way to install Mifiel is quickly and easily with Composer.

To install the most recent version, run the following command.

php composer.phar require mifiel/api-client

Now your composer.json has been updated automatically and you’re able to require the just created vendor/autoload.php file to PSR-4 autoload the library.

You can find the repo at github.com/Mifiel/ruby-api-client.

Python

# Import the Client 
from mifiel import Client

# Configure Mifiel Library, you will 
# pass this to every call you make to our servers.
client = Client(app_id='APP_ID', secret_key='APP_SECRET')
# If you want to make tests without beeing charged
# you can use our sandbox enviroment with:
client.use_sandbox

The best way to install Mifiel lib is with PIP. To install the most recent version please run the following command.

pip install mifiel

You can find the repo at github.com/Mifiel/python-api-client

Authentication

Mifiel uses SHA1 HMAC encryption to authenticate API calls. Each request has to be authenticated by following these steps:

  1. A canonical string is first created using your HTTP headers containing the content-type, content-MD5, request URI and the timestamp. You can replace content-type and content-MD5 with a blank string if needed. The timestamp must be a valid HTTP date. The canonical string is computed as follows:

canonical_string = 'http method,content-type,content-MD5,request URI,timestamp'

  1. This string is then used to create the signature, which is a Base64 encoded SHA1 HMAC, using the APP_SECRET key.

  2. This signature is then added as the Authorization HTTP header in the following form:

Authorization: APIAuth APP-ID:signature-from-step-2

app_id = '<APP_ID>'
app_secret = '<APP_SECRET>'
rest_request = RestClient::Request.new(
  url: 'https://www.mifiel.com/api/v1/documents',
  method: :get,
)
response = ApiAuth.sign!(rest_request, app_id, app_secret).execute
json_response = JSON.load(response)

Ruby Example

If you are using Ruby, we recommend using our official gem.

If you want to create your own, you can use the api-auth gem which supports many popular HTTP clients. In this example we are using the RestClient gem.

Objects

Mifiel data is structured around 3 main types of objects: Document, Certificate and Signature. You’ll find these objects in the format described below.

Document

Contains information about the PDF file being signed

{
  "id": "29f3cb01-744d-4eae-8718-213aec8a1678",
  "original_hash": "e1a580c27d22b4...c537bf90282a6889da",
  "file_file_name": "test-pdf.pdf",
  "signed_by_all": true,
  "signed": true,
  "signed_at": "2016-01-19T16:34:37.921Z",
  "status": [1, "Firmado"],
  "owner": {
    "email": "signer1@email.com",
    "name": "Jorge Morales"
  },
  "callback_url": "https://www.example.com/webhook/url",
  "file": "/api/v1/documents/.../file",
  "file_download": "/api/v1/documents/.../file?download=true",
  "file_signed": "/api/v1/documents/.../file_signed",
  "file_signed_download": "/api/v1/documents/.../file_signed?download=true",
  "file_zipped": "/api/v1/documents/.../zip",
  "signatures": [{
    "email": "signer1@email.com",
    "signed": true,
    "signed_at": "2016-01-19T16:34:37.887Z",
    "certificate_number": "20001000000200001410",
    "tax_id": "AAA010101AAA",
    "signature": "77cd5156779c..4e276ef1056c1de11b7f70bed28",
    "user": {
      "email": "signer1@email.com",
      "name": "Jorge Morales"
    }
  }]
}

Field Type Description
id String
original_hash String Hash of the original (unsigned) document
file_file_name String Name of the uploaded file
signed_by_all Boolean true if all signers have signed the document
signed_at Date Timestamp of date signed (when all signatures have been collected)
already_signed String[] People that have signed
has_not_signed String[] People that have not signed
status Array [code, code_message] 0: not signed, 1: signed
owner Object The owner of the document. The user who created the document.
callback_url String The callback URL to be POSTed when everybody signs
file String Path where the original document can be downloaded
file_signed String Path where the signed file can be downloaded
file_zipped String Path where the file and signed file in a zip file can be downloaded
signatures Object[] Array of a Signature Model

Certificate

Contains information regarding the advanced electronic signatures (e.g. FIEL) used to sign the document

{
  "id": "07320f00-f504-47e0-8ff6-78378d2faca4",
  "type_of": "FIEL",
  "cer_hex": "308204cf30...1303030303030323",
  "owner": "JORGE MORALES MENDEZ",
  "tax_id": "MOMJ811012643",
  "expires_at": "2017-04-28T19:43:23.000Z",
  "expired": false
}
Field Type Description
id String The ID of the Certificate
type_of String Type of certificate used (e.g. FIEL)
owner String Name of the owner as defined in the certificate
tax_id String RFC (tax ID) or other identifier of owner as defined in the certificate
cer_hex String Certificate in hexadecimal
expires_at Date Expiration date of the Certificate
expired Boolean true if the Certificate is expired

Signature

Contains information regarding the signers that have successfully signed the document

{
  "email": "signer1@email.com",
  "signed": true,
  "signed_at": "2016-01-19T16:34:37.887Z",
  "certificate_id": "20001000000200001410",
  "tax_id": "AAA010101AAA",
  "signature": "77cd5156779c..4e276ef1056c1de11b7f70bed28",
  "user": {
    "email": "signer1@email.com",
    "name": "Signer 1"
  }
}
Field Type Description
id String The ID of the Certificate used to sign
email String Email of the signer
signed Boolean true if signed
signed_at Date Timestamp of the date signed
certificate_number String Certificate number assigned by the certificate authority (e.g. SAT)
tax_id String RFC of the signer
signature String Electronic signature on the document (in hexadecimal)

Documents

Create a Document

Send only original_hash and name if you dont want us to have the document.

require 'mifiel'

document = Mifiel::Document.create(
  file: 'path/to/my-file.pdf',
  signatories: [
    { 
      name: 'Signer 1', 
      email: 'signer1@email.com', 
      tax_id: 'AAA010101AAA' 
    }, 
    { 
      name: 'Signer 2', 
      email: 'signer2@email.com', 
      tax_id: 'AAA010102AAA' 
    }
  ],
  callback_url: 'https://www.example.com/webhook/url'
)

# if you dont want us to have the PDF, you can send us 
# the original_hash and the name of the document. Both are required
file_contents = File.read('path/to/my-file.pdf')
original_hash = Digest::SHA256.hexdigest(file_contents)
document = Mifiel::Document.create(
  original_hash: original_hash,
  name: 'my-file.pdf'
  signatories: [ ... ]
)
curl -X POST https://www.mifiel.com/api/v1/documents \
  -F "file=@my-file.pdf" \
  -F "signatories[0][name]=Signer 1" \
  -F "signatories[0][email]=signer@email.com" \
  -F "callback_url=https://www.example.com/webhook/url" \
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Document;

$document = new Document([
  'file_path' => 'path/to/my-file.pdf',
  'signatories' => [
    [ 
      'name' => 'Signer 1', 
      'email' => 'signer1@email.com', 
      'tax_id' =>  'AAA010101AAA' 
    ],
    [ 
      'name' => 'Signer 2', 
      'email' => 'signer2@email.com', 
      'tax_id' =>  'AAA010102AAA'
    ]
  ]
]);
// if you dont want us to have the PDF, you can just send us 
// the original_hash and the name of the document. Both are required
$document = new Document([
  'original_hash' => hash('sha256', file_get_contents('path/to/my-file.pdf')),
  'name' => 'my-file.pdf',
  'signatories' => ...
]);

$document->save();
?>
from mifiel import Document, Client
client = Client(app_id='APP_ID', secret_key='APP_SECRET')

signatories = [
  { 
    'name': 'Signer 1', 
    'email': 'signer1@email.com', 
    'tax_id': 'AAA010101AAA' 
  },
  { 
    'name': 'Signer 2', 
    'email': 
    'signer2@email.com', 
    'tax_id': 'AAA010102AAA'
  }
]
document = Document.create(
  client=client, 
  signatories=signatories, 
  file='test/fixtures/example.pdf'
)
# if you dont want us to have the PDF, you can just send us 
# the original_hash and the name of the document. Both are required
document = Document.create(
  client=client, 
  signatories=signatories, 
  dhash='some-sha256-hash'
)

Create a document to be signed by passing either a PDF file or the Hash of the file.

If you are using our embedded signing widget, we suggest that you pass a File so that it can be displayed to the end user (signer) within the signing flow on your webpage. Also when using the widget you must pass the email of the signer (name is optional) so that we can send them a copy of the signed document when the signing process is complete.

HTTP Request

POST https://www.mifiel.com/api/v1/documents

Parameters

Field Type Description
file String Optional File to be signed (The hash will be automatically extracted from the file and signed)
original_hash String Optional SHA256 encoded Hash of the original, unsigned document (The hash will be signed)
signatories Array A list containing the name, tax_id (RFC) and email of each signer
callback_url String Optional A Callback URL to post when the document gets signed

Response

Returns a Document Model

Get a Specific Document

require 'mifiel'

document = Mifiel::Document.find('29f3cb01-744d-4eae-8718-213aec8a1678')
document.original_hash
document.file
document.file_signed
document.widget_id
# ...
curl "https://www.mfiel.com.mx/api/v1/documents/29f3cb01-744d-4eae-8718-213aec8a1678"
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Document;

$document = Document::find('29f3cb01-744d-4eae-8718-213aec8a1678');
$document->original_hash;
$document->file;
$document->file_signed;
# ...
?>
from mifiel import Document, Client
client = Client(app_id='APP_ID', secret_key='APP_SECRET')

document = Document.find(client, 'id')
document.original_hash
document.file
document.file_signed
# ...

Allows you to retrieve a specific document.

HTTP Request

GET https://www.mifiel.com/api/v1/documents/:id

Response

Returns a Document Models

Get All Documents

require 'mifiel'

documents = Mifiel::Document.all
curl "https://www.mifiel.com/api/v1/documents"
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Document;

$documents = Document::all();
?>
from mifiel import Document, Client
client = Client(app_id='APP_ID', secret_key='APP_SECRET')

documents = Document.all(client)

Allows you to retrieve all documents in your account.

HTTP Request

GET https://www.mifiel.com/api/v1/documents

Response

Returns an Array of Document Model

Delete a Document

require 'mifiel'

Mifiel::Document.delete('29f3cb01-744d-4eae-8718-213aec8a1678')
curl -X DELETE "https://www.mifiel.com/api/v1/documents/29f3cb01-744d-4eae-8718-213aec8a1678"
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Document;

Document::delete('29f3cb01-744d-4eae-8718-213aec8a1678');
?>
from mifiel import Document, Client
client = Client(app_id='APP_ID', secret_key='APP_SECRET')

Document.delete(client, '29f3cb01-744d-4eae-8718-213aec8a1678')

Allows you to delete a specific document in your account.

HTTP Request

DELETE https://www.mifiel.com/api/v1/documents/:id

Request signature

Sends an email request for the document to be signed.

require 'mifiel'

document = Mifiel::Document.find('29f3cb01-744d-4eae-8718-213aec8a1678')
email = 'signer@email.com'
cc = ['signer@email.com', 'viewer@email.com']
document.request_signature(email, cc: cc)
curl -X POST "https://www.mifiel.com/api/v1/documents/29f3cb01-744d-4eae-8718-213aec8a1678/request_signature" \
  -H "Authorization: APIAuth APP-ID:hmac-signature"
from mifiel import Document, Client
client = Client(app_id='APP_ID', secret_key='APP_SECRET')

email = 'signer@email.com'
cc = ['signer@email.com', 'viewer@email.com']
document = Document.find(client, '29f3cb01-744d-4eae-8718-213aec8a1678')
document.request_signature(email, cc=cc)

Response from Mifiel:

  {
    "status": "success",
    "message": "Correo enviado",
    "data": {
      "document": {
        "id": "29f3cb01-744d-4eae-8718-213aec8a1678"        
      }
    }
  }

HTTP Request

POST https://www.mifiel.com/api/v1/documents/:id/request_signature

Parameters

Field Type Description
email String Email of the signer
cc String Email of any non-signing viewers that should receive a copy of the signed document

Certificates

At the moment we only support signing with the FIEL (the most frequently used advanced electronic signature in Mexico). We will soon be adding support for additional types of electronic signatures and will update the documentation as we do so.

Create a Certificate

require 'mifiel'

certificate = Mifiel::Certificate.create(
  file: 'path/to/my-certificate.cer'
)
curl -X POST https://www.mifiel.com/api/v1/keys \
  -F "file=@my-certificate.cer" \
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Certificate;

$certificate = new Certificate([
  'file' => 'path/to/my-certificate.cer'
])
$certificate->save();
?>

Uploads the certificate of a signer in your account.

HTTP Request

POST https://www.mifiel.com/api/v1/keys

Parameters

Field Type Description
file String .cer File of your FIEL

Response

Returns a Certificate Model

Get a Specific Certificate

require 'mifiel'

certificate = Mifiel::Certificate.find('07320f00-f504-47e0-8ff6-78378d2faca4')
certificate.type_of
certificate.owner
certificate.tax_id
# ...
curl "https://www.mfiel.com.mx/api/v1/keys/07320f00-f504-47e0-8ff6-78378d2faca4"
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Certificate;

$certificate = Certificate::find('07320f00-f504-47e0-8ff6-78378d2faca4');
$certificate->cer_hex;
$certificate->type_of;
$certificate->owner;
# ...
?>

Allows you to retrieve a specific certificate.

HTTP Request

GET https://www.mifiel.com/api/v1/keys/:id

Response

Returns a Certificate Model

Get All Certificates

require 'mifiel'

certificates = Mifiel::Certificate.all
curl "https://www.mifiel.com/api/v1/keys"
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Certificate;

$certificates = Certificate::all();
?>

Allows you to retrieve ALL certificates in your account.

HTTP Request

GET https://www.mifiel.com/api/v1/keys

Response

Returns an Array of a Certificate Model

Delete a Certificate

require 'mifiel'

Mifiel::Certificate.delete('07320f00-f504-47e0-8ff6-78378d2faca4')
curl -X DELETE "https://www.mifiel.com/api/v1/keys/07320f00-f504-47e0-8ff6-78378d2faca4"
  -H "Authorization: APIAuth APP-ID:hmac-signature"
<?php
require 'vendor/autoload.php';
use Mifiel\Certificate;

Certificate::delete('id');
?>

Allows you to delete a specific certificate in your account.

HTTP Request

DELETE https://www.mifiel.com/api/v1/keys/:id

Embedded Signing

Widget

Copy this code and paste it just before the </body> tag.

<script type="text/javascript">
  window.mifiel=window.mifiel||[],function(){"use strict";for(var e=["widget"],i=function(e){return function(){window.mifiel.push([e].concat(Array.prototype.slice.call(arguments,0)))}},t=0;t<e.length;t++){var n=e[t];window.mifiel[n]||(window.mifiel[n]=i(n))}if(!document.getElementById("mifiel-js")){var r=document.createElement("script"),o=document.getElementsByTagName("script")[0];r.type="text/javascript",r.id="mifiel-js",r.async=!0,r.src="https://www.mifiel.com/sign-widget-v1.0.0.js",o.parentNode.insertBefore(r,o)}}();
</script>

Then insert the widget in the desired view (page) by including the following snippet:

<script type="text/javascript">
  window.mifiel.widget({
    widgetId: 'c8aa73d1-db06-4d18-9f56-196b00f6eb69',
    appendTo: 'id-of-the-element-to-append',
    successBtnText: 'Proceed to next step'
  });
</script>

The widget is an embedded signing tool that we have created to allow your users to sign documents in an iFrame within your page. By embedding this tool, your users can sign seamlessly without having to leave the flow of your website.

Note: The signers do not have to have an account in mifiel.com

To begin, you have to copy and paste our code snippet (shown to your right) into the code of the page where the signing flow will take place.

You can also find the code snippet here.

Options

Field Type Default Description
widgetId String Widget ID. You can get it with document.widget_id in Ruby
appendTo String body ID of the element in the page
successBtnText String ‘OK’ Text of the button at the end of the signing flow. When the user click
pdf Base64 null Optional PDF in Base64 if you did not send us the PDF when you created the document.
color String 37BC9B Optional Custom color in hexadecimal (e.g. 555555) to personalize the look and feel of your widget. Typically the primary color of your app.
width String 100% Optional Width of the widget [px or %]
height String 1100 Optional Height of the widget [px]

Events

Listen for Mifiel events:

<script type="text/javascript">
window.addEventListener('message', function (e) {
  console.log(e);
  // accept messages from known hosts only
  // change to https://stageex.mifiel.com if necessary
  if (e.origin !== 'https://www.mifiel.com') {
    return;
  }
  // We will always send an object
  if (typeof e.data !== 'object') {
    return;
  }
  // document signed succesfully
  if (e.data.eventType === 'mifiel.widget.success') {
    var data = e.data,
        doc = data.document,
        signature = data.signature;
    // doc.original_hash;
    // doc.file_signed;
  }
  // Event errors
  if (e.data.eventType === 'mifiel.widget.error') {
    var error = e.data.error;
    // error.code => 1001
    // error.message => 'Invalid PDF, the pdf param has no data'
  }
}, false);
</script>

We will send a postMessage to your page to notify any of the events listed below.

In order to secure the events sent by the widget you must verify that the event is coming from our servers.

You can identify the events by e.data.eventType. The success event will have “mifiel.widget.success” and the error events will have “mifiel.widget.error”.

Success event

We will send the document json object and the signature of the user.

Error events

Error events have the property eventType set as “mifiel.widget.error” and a error object (e.data.error) with code and message properties:

Widget setup error events

Event Code Message
Empty PDF 1001 Invalid PDF, the pdf param has no data
Hashes do not match 1002 Invalid PDF, the provided pdf param is not the same as the uploaded one

Note: We send this errors only when you did not send us the PDF when the document was created.

User error events

Event Code Message
Invalid Certificate 2001 Certificate is not valid
Invalid Private Key 2002 Invalid Private Key
Invalid Pasword 2003 Invalid password
Files do not match 2004 .key file does not belong to the .cer file

Server error events

Event Code Message
Signature failure 3002 Fail to sign document

Embedded Signing Flow

Following is a more detailed explanation of the steps involved in requesting and executing signatures within the embedded signing widget.

  1. The first step is to create a Document in your backend with the API_ID and APP_SECRET. You must pass the PDF file that is being signed (or a SHA256 encoded hash of the PDF and the name of the file), along with the following parameters: webhook (callback_url) and the email and name (optional) of each signer.

  2. Mifiel will return a Widget ID in the response, which you will then need to pass to the widget (running on your website’s front-end).

  3. The signature process then takes place within your website. The signer will be able to preview the document, select the files of their FIEL, and enter the password of their FIEL to sign (during this process Mifiel will be verifying that the FIEL is valid and not expired).

  4. If successful, the signer will be presented with a page explaining that the signing was successful and that they will receive an email with the signed document. We will also display a confirmation button (e.g. 'Proceed to next step’) which will return the user to the flow of your website.

  5. Mifiel will then POST the document information to the webhook specified by you (in Step 1): electronic signature of the document, timestamp of signature, the signature page, and information regarding the public certificate(s) used to sign the document.

Errors

Error codes

Mifiel API uses the following error codes:

Error Code Meaning
400 Bad Request – Your request had an error. (more info in the errors response param)
401 Unauthorized – Your authorization header is wrong.
402 Payment Required – Your request requires a paid plan. If you already have a plan, it may have expired.
404 Not Found – The specified object could not be found.
405 Method Not Allowed – You tried to access an invalid method.
406 Not Acceptable – You requested a format that isn’t supported.
410 Gone – The requested object has been removed from our servers.
422 Unprocessable Entity – Something happened when we tried to save your request.
429 Too Many Requests – You’re making too many requests! Slow down!
500 Internal Server Error – We had a problem in our servers. Please try again later.
503 Service Unavailable – We’re temporarily offline for maintenance. Please try again later.

Error Handling

All errors follow the JSend specification. Following are examples of error objects found in the body of error responses (e.g. non-200 status code).

When a client sends an unexpected request:

JSON Example fail response:

  {
    "status": "fail",
    "errors": [
      "Document#29f3cb01-744d-4eae-8718-213aec8a1678 not found"
    ]
  }
Field Type Description
status String fail
errors Array Array of error messages

For server errors:

JSON Example error response:

  {
    "status": "error",
    "message": "500: Internal Server Error" 
  }
Field Type Description
status String error
message String A descriptive message