Skip navigation

Effective October 28, 2019 Duo Security will be transitioning to Cisco's Privacy Statement. View the Duo Privacy Data Sheet.

Documentation

Accounts API

Last Updated: July 9th, 2019

Contents

Please contact your Duo Account Executive or Customer Success Manager if you would like access to this API. If you are an MSP with questions about the Accounts API, please contact the Duo MSP team.

The Accounts API allows a parent account to create, manage, and delete other Duo Security customer accounts.

Overview

The Accounts API enables developers to programmatically create and delete individual Duo customer accounts. Accounts created with an Accounts API application are said to be child accounts of the account to which that application belongs.

Once a customer's Duo account has been created, the Admin API can configure and query the new account. An Account API ikey and skey can authenticate with the Admin API for any child account. When using an Accounts API application all Admin API methods take an additional parameter, account_id, which selects the child account to operate on. Child accounts do not need to add an Admin API application for this to work.

Documented properties will not be removed within a stable version of the API. Once a given API endpoint is documented to return a given property, a property with that name will always appear (although certain properties may only appear under certain conditions, like if the customer is using a specific edition).

Properties that enumerate choices may gain new values at any time, e.g. the device platform value could return new device platforms that did not previously exist. Duo will update our API documentation with new values in a timely fashion.

New, undocumented properties may also appear at any time. For instance, Duo may make available a beta feature involving extra information returned by an API endpoint. Until the property is documented here its format may change or it may even be entirely removed from our API.

First Steps

  1. Sign up for a Duo account.
  2. Log in to the Duo Admin Panel and navigate to Applications.
  3. Click Protect an Application and locate Accounts API in the applications list. Click Protect this Application to get your integration key, secret key, and API hostname. (See Getting Started for help.) Note that only administrators with the Owner role can create or modify an Accounts API application in the Duo Admin Panel.

    Treat your secret key like a password

    The security of your Duo application is tied to the security of your secret key (skey). Secure it as you would any sensitive credential. Don't share it with unauthorized individuals or email it to anyone under any circumstances!

Duo Security has demonstration clients available on Github to call the Duo API methods. Examples are available in: Python, Java, C#, Ruby, and Perl.

Connectivity Requirements

This application communicates with Duo's service on TCP port 443. Firewall configurations that restrict outbound access to Duo's service with rules using destination IP addresses or IP address ranges aren't recommended, since these may change over time to maintain our service's high availability. If your organization requires IP-based rules, please review this Duo KB article.

API Methods

Retrieve Accounts

Returns a list of child accounts.

POST /accounts/v1/account/list

Parameters

None.

Response codes

Response Meaning
200 Success. Returns a list of accounts.

Response format

Key Value
account_id The customer's ID.
name The customer's name.
api_hostname Use this hostname instead of the parent account's when configuring the customer's applications.

Example response

{
  "stat": "OK",
  "response": [{
    "account_id": "DA9VZOC5X63I2W72NRP9",
    "api_hostname": "api-example.duosecurity.com",
    "name": "Extremely Secure Enterprises, Inc."
  }]
}

Create Account

Create a new child account.

POST /accounts/v1/account/create

Parameters

Parameter Required? Description
name Required Name for the new customer.

Response codes

Response Meaning
200 Success. Returns the newly created account.
400 Invalid or missing parameters.

Response format

Same as Retrieve Account.

Example response

{
  "stat": "OK",
  "response": {
    "account_id": "DA9VZOC5X63I2W72NRP9",
    "api_hostname": "api-example.duosecurity.com",
    "name": "Extremely Secure Enterprises, Inc."
  }
}

Delete Account

Delete the account with ID account_id from the system.

POST /accounts/v1/account/delete

Parameters

Parameter Required? Description
account_id Required ID of the account to delete.

Response codes

Response Meaning
200 The account was deleted or did not exist.
409 The account is the parent of one or more child accounts. It cannot be deleted until the child accounts are deleted.

Response format

Empty string.

Example response

{
  "stat": "OK",
  "response": ""
}

Additional Admin API Methods

These Admin API methods are not yet generally available with Accounts API. Please contact Duo Support to request access to these methods.

Get Edition

Returns the edition for a child account.

GET /admin/v1/billing/edition

Parameters

Parameter Required? Description
account_id Required ID of the child account.

Response codes

Response Meaning
200 Success. Returns the edition of the child account.
400 Invalid or missing parameters.
401 Invalid integration key in request credentials.

Response format

Key Value
edition The edition. One of:
  • PERSONAL
  • BUSINESS (legacy plan type)
  • ENTERPRISE
  • PLATFORM
  • BEYOND

Example response

{
  "stat": "OK",
  "response": {"edition": "PLATFORM"}
}

Set Edition

Sets the edition for a child account.

POST /admin/v1/billing/edition

Parameters

Parameter Required? Description
account_id Required ID of the child account.
edition Required The edition to set. This should be one of:
  • ENTERPRISE
  • PLATFORM
  • BEYOND

Response codes

Response Meaning
200 Success.
400 Invalid or missing parameters.
401 Invalid integration key in request credentials.

Response format

The response is empty.

Example response

{
  "stat": "OK",
  "response": ""
}

Get Telephony Credits

Returns the available telephony credits for a child account.

GET /admin/v1/billing/telephony_credits

Parameters

Parameter Required? Description
account_id Required ID of the child account.

Response codes

Response Meaning
200 Success. Returns the available telephony credits of the child account.
400 Invalid or missing parameters.
401 Invalid integration key in request credentials.

Response format

Key Value
credits The available telephony credits.

Example response

{
  "stat": "OK",
  "response": {"credits": 10}
}

Set Telephony Credits

Sets the telephony credits for a child account.

Any additional credits added to the child account are transferred from the parent account. For example, if the child account has 100 credits and it is then set to 300 credits, then 200 credits are deducted from the parent's balance and added to the child's balance.

POST /admin/v1/billing/telephony_credits

Parameters

Parameter Required? Description
account_id Required ID of the child account.
credits Required The total number of credits that the child account will have after transferring credits from the parent account.

Response codes

Response Meaning
200 Success.
400 Invalid or missing parameters.
401 Invalid integration key in request credentials.

Response format

Response format

Key Value
credits_added The the number of telephony credits that were added to the child account and deducted from the parent account.

Example response

{
  "stat": "OK",
  "response": {"credits_added":10}
}

API Details

Base URL

All API methods use your API hostname, https://api-XXXXXXXX.duosecurity.com.

Methods always use HTTPS. Unsecured HTTP is not supported.

Request Format

All requests must have "Authorization" and "Date" headers.

If the request method is GET or DELETE, URL-encode parameters and send them in the URL query string like this: /accounts/v1/account/list?realname=First%20Last&username=root. They still go on a separate line when creating the string to sign for an Authorization header.

Send parameters for POST requests in the body as URL-encoded key-value pairs (the same request format used by browsers to submit form data). The header "Content-Type: application/x-www-form-urlencoded" must also be present.

When URL-encoding, all bytes except ASCII letters, digits, underscore ("_"), period ("."), tilde ("~"), and hyphen ("-") are replaced by a percent sign ("%") followed by two hexadecimal digits containing the value of the byte. For example, a space is replaced with "%20" and an at-sign ("@") becomes "%40". Use only upper-case A through F for hexadecimal digits.

Response Format

Responses are formatted as a JSON object with a top-level stat key.

Successful responses will have a stat value of "OK" and a response key. The response will either be a single object or a sequence of other JSON types, depending on which endpoint is called.

{
  "stat": "OK",
  "response": {
    "key": "value"
  }
}

Values are returned as strings unless otherwise documented.

Unsuccessful responses will have a stat value of "FAIL", an integer code, and a message key that further describes the failure. A message_detail key may be present if additional information is available (like the specific parameter that caused the error).

{
  "stat": "FAIL",
  "code": 40002,
  "message": "Invalid request parameters",
  "message_detail": "username"
}

The HTTP response code will be the first three digits of the more specific code found inside the JSON object. Each endpoint's documentation lists HTTP response codes it can return. Additionally, all API endpoints that require a signed request can return the following HTTP response codes:

Response Meaning
200 The request completed successfully.
401 The "Authorization", "Date", and/or "Content-Type" headers were missing or invalid.
403

This integration is not authorized for this endpoint or the ikey was created for a different integration type (for example, using an Auth API ikey with Admin API endpoints).

405 The request's HTTP verb is not valid for this endpoint (for example, POST when only GET is supported).
429 The account has made too many requests of this type recently. Try again later.

Authentication

The API uses HTTP Basic Authentication to authenticate requests. Use your Duo application's integration key as the HTTP Username.

Generate the HTTP Password as an HMAC signature of the request. This will be different for each request and must be re-generated each time.

To construct the signature, first build an ASCII string from your request, using the following components:

Component Description Example
date The current time, formatted as RFC 2822. This must be the same string as the "Date" header. Tue, 21 Aug 2012 17:29:18 -0000
method The HTTP method (uppercase) POST
host Your API hostname (lowercase) api-xxxxxxxx.duosecurity.com
path

The specific API method's path

/accounts/v1/account/list
params The URL-encoded list of key=value pairs, lexicographically sorted by key. These come from the request parameters (the URL query string for GET and DELETE requests or the request body for POST requests). If the request does not have any parameters one must still include a blank line in the string that is signed. Do not encode unreserved characters. Use upper-case hexadecimal digits A through F in escape sequences. realname=First%20Last&username=root

Then concatenate these components with (line feed) newlines. For example:

Tue, 21 Aug 2012 17:29:18 -0000
POST
api-xxxxxxxx.duosecurity.com
/accounts/v1/account/list
realname=First%20Last&username=root

GET requests also use this five-line format:

Tue, 21 Aug 2012 17:29:18 -0000
GET
api-xxxxxxxx.duosecurity.com
/accounts/v1/account/list
username=root

Lastly, compute the HMAC-SHA1 of this canonical representation, using your Duo application's secret key as the HMAC key. Send this signature as hexadecimal ASCII (i.e. not raw binary data). Use HTTP Basic Authentication for the request, using your integration key as the username and the HMAC-SHA1 signature as the password.

For example, here are the headers for the above POST request to api-XXXXXXXX.duosecurity.com/accounts/v1/account/list, using DIWJ8X6AEYOR5OMC6TQ1 as the integration key and Zh5eGmUq9zpfQnyUIu5OL9iWoMMv5ZNmk3zLJ4Ep as the secret key:

Date: Tue, 21 Aug 2012 17:29:18 -0000
Authorization: Basic RElXSjhYNkFFWU9SNU9NQzZUUTE6MmQ5N2Q2MTY2MzE5NzgxYjVhM2EwN2FmMzlkMzY2ZjQ5MTIzNGVkYw==
Host: api-XXXXXXXX.duosecurity.com
Content-Length: 35
Content-Type: application/x-www-form-urlencoded

Separate HTTP request header lines CRLF newlines.

The following Python function can be used to construct the "Authorization" and "Date" headers:

import base64, email, hmac, hashlib, urllib

def sign(method, host, path, params, skey, ikey):
    """
    Return HTTP Basic Authentication ("Authorization" and "Date") headers.
    method, host, path: strings from request
    params: dict of request parameters
    skey: secret key
    ikey: integration key
    """

    # create canonical string
    now = email.Utils.formatdate()
    canon = [now, method.upper(), host.lower(), path]
    args = []
    for key in sorted(params.keys()):
        val = params[key]
        if isinstance(val, unicode):
            val = val.encode("utf-8")
        args.append(
            '%s=%s' % (urllib.quote(key, '~'), urllib.quote(val, '~')))
    canon.append('&'.join(args))
    canon = '\n'.join(canon)

    # sign canonical string
    sig = hmac.new(skey, canon, hashlib.sha1)
    auth = '%s:%s' % (ikey, sig.hexdigest())

    # return headers
    return {'Date': now, 'Authorization': 'Basic %s' % base64.b64encode(auth)}

Troubleshooting

Need some help? Take a look at our Accounts API Knowledge Base articles or Community discussions. For further assistance, contact Support.