April 2, 2013

Beginner

How To Use the DigitalOcean API

About the DigitalOcean API


The DigitalOcean API provides a complete way to manage your DigitalOcean assets without the control panel.

Any action you can perform to your droplets, images, and SSH keys can also be done with the API, as described here.

In order to use the API, you need your client key and API key.

Step One - Create your API key


Before we do anything with the API, we'll need an API key associated with a client key.

From your control panel, click on the "My Settings" link in the left-hand sidebar. In your settings, click "API Access".

API Access

Take note of your client key; it's unique to your account and should be kept private.

At this point, you don't have an API key yet, so let's make one by clicking "Generate a new API Key".

When your API key appears, be sure to take note of it. It will never be visible on this page again.

Both a client key and its associated API key are required to use the API. It's important not to forget them.

Step Two - Use the API


The entire API specification can be found here.

All API requests are in the form:
https://api.digitalocean.com/[API_resource]/?client_id=[YOUR_CLIENT_ID]&api_key=[YOUR_API_KEY]&[request_info]

For example, to list all of your droplets and their information:
https://api.digitalocean.com/droplets/?client_id=QWeRtyUIoPASDFGhJk1lz&api_key=dummyOwkdBo1Bwdcfoj8oBNkwoAQ17dvbwJWOkdLh

Using Wrappers for the API


A variety of wrappers exist for the API in different languages. These can be found on GitHub and can be useful for integrating the API into a script or program.

Here is an example of using the API using a Python wrapper, dop, provided by Antonio Montero.

To install Python packages, the preferred method is pip. Install it with:
curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
sudo python get-pip.py

Next, we can install dop using pip:
pip install dop

In the Python interactive shell, we can see how it works:
Python 2.7.3 (default, Aug  1 2012, 05:16:07)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from dop.client import Client
>>> client = Client('QWeRtyUIoPASDFGhJk1lz', 'dummyOwkdBo1Bwdcfoj8oBNkwoAQ17dvbwJWOkdLh')
>>> droplets = client.show_active_droplets()
>>> for droplet in droplets:
...     print droplet.to_json()
...
{'status': u'active', 'region_id': 1, 'event_id': 11, 'size_id': 66, 'image_id': 1234, 'backups_active': True, 'ip_address': u'1.2.3.4', 'id': 12345, 'name': u'test1'}
{'status': u'active', 'region_id': 1, 'event_id': 21, 'size_id': 66, 'image_id': 4321, 'backups_active': True, 'ip_address': u'1.2.3.5', 'id': 54321, 'name': u'test2'}
{'status': u'active', 'region_id': 1, 'event_id': 31, 'size_id': 64, 'image_id': 4444, 'backups_active': None, 'ip_address': u'1.2.3.6', 'id': 55555, 'name': u'test3'}

You can leverage any wrapper to your advantage in an automated environment.

Caveats


Currently, the API (even the control panel) does not support resizing droplets to 96 GB droplets.

Resizes through the API are performed with the "fast-resize" as shown in the control panel. Therefore, resizing a droplet through the API will not change its disk space.

At present, API calls to a non-existent droplet, image, size, or region will return a 200 OK status code with a JSON response including an "error_message" key.

Share this Tutorial

Vote on Hacker News

Try this tutorial on an SSD cloud server.

Includes 512MB RAM, 20GB SSD Disk, and 1TB Transfer for $5/mo! Learn more

Create an account or login:

38 Comments

Write Tutorial
  • Gravatar developer 11 months

    Hi, I have a question about using the API's interacting with the Power_Off and Power_On and billing. You have a great service though at this point I just use it as a hobbyist doing some prototyping. I don't need my server up and running 24/7. If I use the Power_Off API to turn off my server when I am not using it, does that mean I am not billed hours? I can whip up a quick app that uses these APIs to boot the server up when I need it and power it down when I don't - optimizing my bill. If I still get billed in the Power_Off state then I'll just leave it running (like it has for the last 6 months).

  • Gravatar peapodamus 11 months

    In order to not be billed, the droplet must be destroyed.

  • Gravatar Kamal Nasser 10 months

    You are billed for powered off droplets as your diskspace, CPU, RAM, and IP address are all reserved while your Droplet is powered off. If you want to save a Droplet for future use take a snapshot of it and then destroy it. You'll be able to create a new Droplet from the snapshot image anytime to bring it back online.

  • Gravatar sf 10 months

    GET for destructive (or even non-idempotent) methods ? You must be kidding ?!?

  • Gravatar Kamal Nasser 10 months

    @sf All API actions are GET at the moment.

  • Gravatar Jason Mulligan 10 months

    Why are they misused at all? This is like an HTTP 1.0 API.

  • Gravatar skunkwrkz 9 months

    Creates api, community complains...

  • Gravatar scribblet 9 months

    So unless I regularly change my API key as I can't change my Client ID, any forward proxy between my computer and your network (i.e., the NSA, your upstream provider, mine, my work systems admin, etc) that logs HTTP requests will forever store my credentials that expose and provide full control over my Droplets. Great! Sign me up!

  • Gravatar Kamal Nasser 9 months

    @scribblet: The API forces SSL/HTTPS so unless the NSA, your upstream provider, our upstream provider, your work sysadmins, or etc. have our private key, they can't read the data they see as it will be encrypted.

  • Gravatar Artem Zaytsev 9 months

    Hi, I found a mistake in the status of the request if an error occurred. For example, a request to a non-existent entity (/droplets, /regions, /images or /sizes): % curl -i 'https://api.digitalocean.com/droplets/999999?client_id=xxx&api_key=xxx' HTTP/1.1 200 OK Status: 200 OK {"status": "ERROR", "error_message": "No Droplets Found"} As you can see, status = 200 instead of 404 and error message is stored in the "error_message" instead of "message" as explained in https://api.digitalocean.com/. On the other hand, the response format for /ssh_keys and /domains is correct.

  • Gravatar Kamal Nasser 9 months

    Thanks @Artem, I'll mention this to our devs. :]

  • Gravatar scribblet 9 months

    @Kamal Touche! I much prefer the OAuth2 approach of using auto-expiring keys that need to be recreated using private credentials from both parties. However, your point is entirely valid and I retract my previous criticism. Personally, I believe over-reliance on SSL for security may become a point of vulnerability later on. Specifically, RC4 and the BEAST attack. I applaud your use of perfect forward secrecy though!

  • Gravatar tkoder 7 months

    Are there any plans for allowing multiple (labelled) API keys? It feels a bit awkward if I'll be forced to use a single key across multiple applications.

  • Gravatar Kamal Nasser 7 months

    @tkoder: It's not planned at the moment. Please create a uservoice suggestion: https://digitalocean.uservoice.com/forums/136585-digital-ocean

  • Gravatar mikael.chojnacki 7 months

    Is there any way to "beta" test the API when building a application on top of it? I can't seem to find any way to test the different api calls without it going to the production environment.

  • Gravatar Kamal Nasser 7 months

    @mikael.chojnacki: That is currently not possible however you can create new small droplets and since you are charged by the hour it wouldn't cost you very much. ($0.007/hr)

  • Gravatar mikael.chojnacki 7 months

    Yeah that's what I'm doing currently :) Are there any plans to date open up for a testing server for the API and maybe some sort of reseller account?

  • Gravatar Kamal Nasser 7 months

    We're currently not planning to implement reseller accounts.

  • Gravatar djdiramio 5 months

    Is there a way to create a new droplet through the API with the pre-installed application configuration (i.e. LAMP on Ubuntu 12.04 or WordPress or Ubuntu 12.10)? Do they each have an image_id we can use?

  • Gravatar Kamal Nasser 5 months

    @djdiramio: Yes. Each of those has its own image ID that you can query by performing a GET request against /images.

  • Gravatar david.cheney 5 months

    Using an API key in a GET query parameter is definitely a bad practice, but you should be okay as long as you never use it from a browser. If you do use your API key in a browser, then you are susceptible to browser history attacks, referrer attacks, CSRF, and exfiltration attacks.

  • Gravatar Kamal Nasser 5 months

    @david.cheney: That is correct, we're working on API v2 which will be a fully RESTful API. Nevertheless, I don't see how CSRF attacks apply in this case. Well, it does, however, so do all APIs.

  • Gravatar edd 4 months

    It would be really useful if there was a stubbed instance of the API (i.e. one which could be used as a test harness without actually creating any droplets). This would also be very useful for running continuous integration tests of our api related code against. Do you have any plans to implement anything like this?

  • Gravatar ananthdeodhar 4 months

    +1 edd - A test server would be REALLY helpful to test all the API features on!

  • Gravatar diego.lopez002 4 months

    Hi Digital Ocean Community, Being a newbie to this community and these technical write-ups, I have the following suggestion -- since Linux has all kinds of distributions, which leverage all kinds of package-managers, would it be too much burden to the authors of these write-ups if they specify OS release version, where the write-up was tested towards the top of the article? I sometimes spend more time figuring out some differences in the Linux distro that distracts me from learning the overall task being described in the write-up. Thank you for your time. Cheers.

  • Gravatar Kamal Nasser 4 months

    Hi diego.lopez002, thanks for the feedback. This article is OS-generic as it tells you how to use our API to manage droplets. Pretty much all of the other articles that deal with a specific OS have that OS in the title.

  • Gravatar agentofkaos 3 months

    How do I programmatically determine what sizes are available for specific region via the DO API? For example, at the time of this question, "New York 1" doesn't allow droplet sizes 16 GB / 8 CPU or greater. There is no (documented) "by region" filter option in the DO GET /size API. Trial and error with DO GET /droplets/new and ratcheting down the size until one works seems a bit much. Cheers.

  • Gravatar Kamal Nasser 3 months

    @agentofkaos: That is not possible yet however please vote for the uservoice suggestion http://digitalocean.uservoice.com/forums/136585-digitalocean/suggestions/3709470-expose-additional-meta-data-about-server-sizes-in-.

  • Gravatar marek.jalovec 3 months

    Can you please post all possible values in "status" field in droplet detail? thanks btw sorry for incomplete post, please delete it. thanks

  • Gravatar Kamal Nasser 3 months

    @marek.jalovec: Please open up a support ticket. Meanwhile, the only statuses that I know of are: active, off, and archived.

  • Gravatar agentofkaos 3 months

    Thanks, Kamal - request crossed over to your uservoice entry and voted for.

  • Gravatar makeittotop 4 days

    When I try and access my droplets via curls, I always invariably end up with a "Access Denied" json message. curl -i "https://api.digitalocean.com/droplets/?client_id=[**]&api_key=[**]" -u "user:pass" HTTP/1.1 401 Unauthorized Server: cloudflare-nginx Date: Mon, 14 Apr 2014 10:16:43 GMT Content-Type: application/json; charset=utf-8 ... Status: 401 Unauthorized ... {"status":"ERROR","error_message":"Access Denied","message":"Access Denied"} Though this works fine inside a language. Why is that?

  • Gravatar Travis Johnston 3 days

    I am trying to connect to the api using jquery and Ajax. I can connect but I can't display anything because it says the following in the console: Uncaught SyntaxError: Unexpected token : api.digitalocean.com/:1

  • Gravatar Andrew SB 3 days

    @makeittotop: Double check your client id and api key. I get the correct response using the same command with my key/id. @Travis: That sounds like a problems with your code. Could you show us a snippet so we can help figure out what's happening?

  • Gravatar Travis Johnston 3 days

    Sure @astarr function loadDigital() { var clientID = "id here"; var apiKey = "key here"; //Requested URL var requestedURL = "https://api.digitalocean.com/droplets/?client_id="+clientID+"&api_key="+apiKey+"&format=json&jsoncallback=? "; // Request the JSON and process it $.ajax({ type:'GET', url: requestedURL, dataType:'jsonp', success:function(results) { $(".status").html(results); } }); }

  • Gravatar Andrew SB 3 days

    @Travis So you're trying to do this in the browser? Right now the API only supports JSON, not JSONP. There is no format parameter. So unfortunately, you'll run into issues with cross origin policy in most browsers. I'd recommend moving this into your backend code if this is web-based. If you're doing a browser plugin, there are ways to work around this by asking for certain permissions.

  • Gravatar Travis Johnston 3 days

    @astarr, That's weird because when I leave it as jsonp, it at least connects and I can see the data in the console, once I click the document that "api.digitalocean.com/:1" that the error is referencing. If I change the datatype to json, it breaks completely and gives me: "XMLHttpRequest cannot load https://api.digitalocean.com/droplets/?client_id=(stuff)&api_key=(stuff)&format=json&jsoncallback=?. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. I'm pretty new to working with APIs and AJAX, but from what I read adding the callback should fix any cross domain issues though. When you say backend, do you mean doing this using PHP instead of AJAX?

  • Gravatar Andrew SB 2 days

    I mean executing the code on the server side instead of in the user's browser. The original error is because your code is expecting JSONP, but since there is no format parameter, the API ignores that and returns JSON. The error you see when you change the data type to JSON is from your browser itself. It is blocking the request due to the Same Origin Policy: http://en.wikipedia.org/wiki/Same_origin_policy

Leave a Comment

Create an account or login:
Ajax-loader