Authenticated Routes

Introduction

API Keys alone do not provide complete security, we use them as a way to identify the calling client, but not for authentication and authorization. Here is an article to read more about why:

API Keys ≠ Security: Why API Keys Are Not Enough | Nordic APIs |

To provide additional security we use the API Key together with the JWT authentication scheme (for third-party non-browser clients). Some routes might be protected to only authorized users. To read more about JWT in the following article:

Refresh Tokens: When to Use Them and How They Interact with JWTs

How does it work?

Use the provided email and password credentials to obtain an Access token.

This token will authenticate the request and grant you authorization to call the Vitau API’s protected resources, therefore, it should be included within the header of each request.

Access tokens must be short lived, decoding the token will show the access_lifetime field in seconds. For example, an expiry value of 3600 expires in one hour. To handle token expiration you might want to:

  • Set a timer to update the access token before it expires.
  • Keep track of obtained time + access_lifetime.

Re-use the access token until it expires, then get a new token.

See more of decoding-encoding jwt: JWT IO

Obtaining token

Request:
curl --request POST \\
  --url API_URL/api/token/ \\
  --header 'Accept: application/json' \\
	--header 'Content-Type: application/json' \\
  --header 'X-API-Key: Client API Key'
	--data '{"email":STRING, "password": STRING}'

Response:
Status Code: 200 OK
{
  "access" TOKEN
}

Responses

StatusMeaning
200 OKAuthentication completed successfully and you’ll receive a valid access token.
401 UnauthorizedThe given email/password pair is not correct.

Prove authentication

The access token must be present in the Authorization header.

Request:
curl --request GET \\
  --url API_URL/api/some-route/ \\
  --header 'Accept: application/json' \\
  --header 'X-API-Key: Client API Key' \\
  --header 'Authorization: Bearer {ACCESS_TOKEN}'

An expired token will return 401 Unauthorized

Orders

An order is a customer’s request to purchase products from Vitau. The Order object consists primarily of:

  • Patient’s personal information
  • Delivery address. (This might also be picked up at Vitau Store).
  • Details is an array with the quantity of each product to be purchased
  • Payment method
  • Relevant dates such as creation, expected delivery, etc.
  • Invoicing details. (Optional)
  • Order status
  • Payment status

CREATE

This service creates an ORDER object, along with the USER, SHIPPING, and INVOICING information if they’re included within the payload.

The products and quantities of the Order are specified inside an array of DETAIL objects. Each detail has {"product": ID, "quantity":INT}.

The payment_method ID must be the one given along with the Client’s API KEY.

Request objects:

  • USER
    • ”email”: STRING & UNIQUE
    • ”phone”: UNIQUE, Format: +(COUNTRY-CODE)(PHONE) e.g. +528188888888
    • ”first_name”: STRING
    • ”last_name”: STRING
  • INVOICING
    • ”full_name”: STRING
    • ”email”: STRING
    • ”rfc”: STRING
    • ”street”: STRING
    • ”exterior_number”: STRING
    • ”neighborhood”: STRING
    • ”city”: STRING
    • ”state”: STRING
    • ”country”: STRING
    • ”zipcode”: STRING
  • SHIPPING
    • ”street”: STRING
    • ”exterior_number”: STRING
    • ”interior_number”: STRING
    • ”neighborhood”: STRING
    • ”city”: STRING
    • ”state”: STRING
    • ”country”: STRING
    • ”zipcode”: STRING
    • ”phone”: STRING
  • PRESCRIPTION
    • ”document”: BASE64 STRING
    • ”document_name”: STRING OPTIONAL
    • ”issue_date”: DATE (Y-m-d)
    • “expiring_date”: DATE (Y-m-d) OPTIONAL

Purchase order status ENUM values:

  • patient_order_status
    • ”in_process” : The order has been created successfully.
    • ”shipped”: The order has been dispatched and is on its way.
    • ”delivered”: The order has been delivered to the client.
    • ”cancelled”: The order has been cancelled.
  • payment_status
    • ”unpaid”: The order has not been paid.
    • ”credit”: The order is placed under credit and will be paid within a specified timeframe.
    • ”paid”: The order has been paid.
    • ”rejected”: The payment processor rejected the transaction.
    • ”in_process”: The payment processor is processing the transaction.
Request:
curl --request POST \\
  --url API_URL/api/orders/resources/ \\
  --header 'Accept: application/json' \\
  --header 'X-API-Key: {Client API Key}' \\
	--header 'Authorization: Bearer {ACCESS_TOKEN}'
	--data \\
		{
		"user":  USER, REQUIRED,
		"invoicing": INVOICING, OPTIONAL, // Sending invoicing info. will generate and send the invoice
		"order": {
			"details":[{"product":INT,"quantity":INT} ...], REQUIRED
			"shipping": SHIPPING, OPTIONAL
			"shipping_method": INT, OPTIONAL // Selected shipping method from the valid methods for this zip code.
			"store": 1, OPTIONAL, // To be picked up at Vitau's store.
			"payment_method": INT, REQUIRED,
			"coupon": STRING, OPTIONAL // Coupon code,
			"prescriptions":[ PRESCRIPTION ], OPTIONAL // Array of PRESCRIPTION objects
			"comments": TEXT, OPTIONAL,
			}
		}

Response:
Status Code: 201 Created
{
"subtotal": DOUBLE,
"shipping_price": DOUBLE,
"shipping_discount": DOUBLE,
"coupon": {
	"code": STRING,
	"value": DOUBLE // Between 0 and 1 is a percentage, else has a fixed value.
},
"discount":DOUBLE,
"iva":DOUBLE,
"total": DOUBLE,
"selected_shipping_method": INT,
"expected_delivery_date": UTC DATETIME,
"max_delivery_date": UTC DATETIME,
"details":
	[{
    "product": INT,
    "quantity": INT,
    "subtotal": DOUBLE,
    "discount": DOUBLE,
    "iva":DOUBLE,
    "total": DOUBLE
	}...],
"shipping": SHIPPING,
"store": STORE,
"patient_order_status": "in_process",
"payment_status": ENUM,
...
}

Error messages

StatusMeaning
400 Bad RequestThis response may be the result if any value from the payload is missing or incorrect, and the service will respond with the corresponding message explaining the error.
201 Created. Invoice errorWhen generating an invoice fails the order will be created along with the other resources, however the order will not have a value in the cfdi attribute, and the email will not be sent.
201 Created. Coupon invalidAs with calculate, the order will be created along with the other resources, however, it will not have a value in the coupon attribute, and the corresponding discount will not be applied.

GET

  • Searchable lookup fields
    • Patient’s full name
  • Filterable fields
    • patient=INT
    • order_status__in=ENUMs separated by commas
    • exclude_order_status__in=ENUMs separated by commas
    • payment_status__in=ENUMs separated by commas
    • expected_delivery_date_before DATE
    • expected_delivery_date_after DATE
    • max_delivery_date_before DATE
    • max_delivery_date_after DATE
  • Ordering fields
    • created_at This is the default by descending order
    • expected_delivery_date
Request:
curl --request GET \\
  --url API_URL/api/orders/ \\
  --header 'Accept: application/json' \\
  --header 'X-API-Key: {Client API Key}' \\
	--header 'Authorization: Bearer {ACCESS_TOKEN}'

Response:
Status Code: 200 OK
{
"count": INT,
"next": "API_URL/api/orders/?page=2",
"previous": null,
"results": [
      {
        "id": INT,
        "created_at": DATETIME,
        "order_status": ENUM,
        "patient_order_status": ENUM,
        "patient": STRING,
        "payment_status": ENUM,
        "products_count": INT,
        "details": [{"default_image": URL,"quantity": INT}],
        "shipping": {"street": STRING,"exterior_number": STRING,"city": STRING},
        "payment_method": STRING,
        "total": DOUBLE,
        "origin": STRING,
        "expected_delivery_date": DATETIME,
        "max_delivery_date": DATETIME,
      },
	...,
	]
}

Details

You might want to fetch a specific order and view more details.

The API will respond with 404 if the order is not found or you don’t have permission to view it.

Request:
curl --request GET \\
  --url API_URL/api/orders/{orderID} \\
  --header 'Accept: application/json' \\
  --header 'X-API-Key: {Client API Key}' \\
	--header 'Authorization: Bearer {ACCESS_TOKEN}'

Response:
Status Code: 200 OK
{
"count": INT,
"next": "API_URL/api/orders/?page=2",
"previous": null,
"results": [
      {
        "id": INT,
		    "details": [{
						"id": INT,
						"product": PRODUCT,
            "price": DOUBLE,
            "subtotal": DOUBLE,
            "total": DOUBLE,
            "discount": DOUBLE,
            "iva": DOUBLE,
            "quantity": INT
        }],
		    "patient": {
					"id": INT,
					"user": USER,
	        "default_shipping": INT,
	        "default_invoicing": INT,
	        "preferred_payment": INT
		    },
		    "shipping": SHIPPING,
		    "store": INT,
		    "payment": INT,
		    "payment_references": [REFERENCE],
		    "payment_method": PAYMENT_METHOD,
		    "coupon": COUPON,
		    "generated_by": USER,
		    "updated_by": USER,
		    "invoicing": INT,
		    "payment_date": DATETIME,
		    "shipping_date": DATETIME,
		    "expected_delivery_date": DATETIME,
		    "max_delivery_date": DATETIME,
		    "receiving_date": DATETIME,
		    "patient_order_status": ENUM,
		    "prescriptions": [PRESCRIPTION],
		    "shipping_method": SHIPPING_METHOD,
		    "created_at": DATETIME,
		    "updated_at": DATETIME,
		    "insurance_refund_status": ENUM,
		    "order_status": ENUM,
		    "payment_status": ENUM,
		    "rejection_reason": STRING,
		    "origin": STRING,
		    "subtotal": DOUBLE,
		    "iva": DOUBLE,
		    "shipping_price": DOUBLE,
		    "shipping_discount": DOUBLE,
		    "shipping_cost": DOUBLE,
		    "discount": DOUBLE,
		    "total": DOUBLE,
		    "cfdi": STRING,
		    "reminder": REMINDER
      },
	...,
	]
}

UPDATE

After the order is created you may only change the products if the status is quoted or approved. The URL includes the ID of the order to be modified. As you may only edit certain attributes we recommend using PATCH.

Request:
curl --request PATCH \\
  --url API_URL/api/orders/{orderID}/ \\
  --header 'Accept: application/json' \\
  --header 'X-API-Key: {Client API Key}' \\
	--header 'Authorization: Bearer {ACCESS_TOKEN}'
	--data \\
		{
		// This array will override the existing order details and recalculate totals
		"details":[{"product":INT,"quantity":INT} ...]
		}

Response:
Status Code: 200 OK
{
"subtotal": DOUBLE,
"shipping_price": DOUBLE,
"shipping_discount": DOUBLE,
"coupon": {
	"code": STRING,
	"value": DOUBLE // Between 0 and 1 is a percentage, else has a fixed value.
},
"discount":DOUBLE,
"iva":DOUBLE,
"total": DOUBLE,
"selected_shipping_method": INT,
"expected_delivery_date": UTC DATETIME,
"max_delivery_date": UTC DATETIME,
"details":
	[{
    "product": INT,
    "quantity": INT,
    "subtotal": DOUBLE,
    "discount": DOUBLE,
    "iva":DOUBLE,
    "total": DOUBLE
	}...],
"shipping": SHIPPING,
"store": STORE,
"patient_order_status": "in_process",
"payment_status": ENUM,
...
}

Besides updating the order details you can also cancel the order when we have not started building or dispatching it. Simply, send the order status with value cancelled . This operation cannot be undone.

Request:
curl --request PATCH \\
  --url API_URL/api/orders/{orderID}/ \\
  --header 'Accept: application/json' \\
  --header 'X-API-Key: {Client API Key}' \\
	--header 'Authorization: Bearer {ACCESS_TOKEN}'
	--data \\
		{
			"order_status": "cancelled"
		}

Response:
Status Code: 200 OK

Request Invoice

After creating an order you may request to generate an invoice simply by sending the ID of the corresponding invoicing information, however, there are some limitations:

  • After creating the order you have up to 3 days
  • Orders of past months cannot request invoice
  • INVOICING
    • ”full_name”: STRING
    • ”email”: STRING
    • ”rfc”: STRING
    • ”street”: STRING
    • ”exterior_number”: STRING
    • ”neighborhood”: STRING
    • ”city”: STRING
    • ”state”: STRING
    • ”country”: STRING
    • ”zipcode”: STRING
    • ”cfdi_use”: STRING
    • ”fiscal_regime”: STRING

Example request:

Request:
curl --request PUT \\
  --url API_URL/api/orders/{orderID}/request-invoice/ \\
  --header 'Accept: application/json' \\
  --header 'X-API-Key: {Client API Key}' \\
	--header 'Authorization: Bearer {ACCESS_TOKEN}'
	--data \\
		{
			"invoicing": INVOICING
		}

Response:
Status Code: 200 OK