"Fossies" - the Fresh Open Source Software Archive

Member "vagrant-2.2.14/website/pages/vagrant-cloud/api.mdx" (20 Nov 2020, 39437 Bytes) of package /linux/misc/vagrant-2.2.14.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "api.mdx": 2.2.10_vs_2.2.11.

    1 ---
    2 layout: vagrant-cloud
    3 page_title: Vagrant Cloud API
    4 sidebar_title: API
    5 ---
    6 
    7 # Vagrant Cloud API
    8 
    9 ## Using the API
   10 
   11 Vagrant Cloud provides an API for users to interact with Vagrant Cloud for experimentation, automation, or building new features and tools on top of our existing application.
   12 
   13 ### Authentication
   14 
   15 Some API endpoints require authentication to create new resources, update or delete existing resources, or to read a private resource.
   16 
   17 Clients can authenticate using an authentication token.
   18 The token can be passed to Vagrant Cloud one of two ways:
   19 
   20 1. (Preferred) Set the `Authorization` header to `"Bearer "` and the value of the authentication token.
   21 2. Pass the authentication token as an `access_token` URL parameter.
   22 
   23 Examples below will set the header, but feel free to use whichever method is easier for your implementation.
   24 
   25 -> The `X-Atlas-Token` header is also supported for backwards-compatibility.
   26 
   27 ### Request and Response Format
   28 
   29 Requests to Vagrant Cloud which include data attributes (`POST` or `PUT`/`PATCH`) should set the `Content-Type` header to `"application/json"`, and include a valid JSON body with the request.
   30 
   31 JSON responses may include an `errors` key, which will contain an array of error strings, as well as a `success` key.
   32 For example:
   33 
   34 ```json
   35 {
   36   "errors": ["Resource not found!"],
   37   "success": false
   38 }
   39 ```
   40 
   41 ### Response Codes
   42 
   43 Vagrant Cloud may respond with the following response codes, depending on the status of the request and context:
   44 
   45 #### Success
   46 
   47 ##### **200** OK
   48 
   49 ##### **201** Created
   50 
   51 ##### **204** No Content
   52 
   53 #### Client Errors
   54 
   55 ##### **401** Unauthorized
   56 
   57 You do not have authorization to access the requested resource.
   58 
   59 ##### **402** Payment Required
   60 
   61 You are trying to access a resource which is delinquent on billing.
   62 Please contact the owner of the resource so that they can update their billing information.
   63 
   64 ##### **403** Forbidden
   65 
   66 You are attempting to use the system in a way which is not allowed.
   67 There could be required request parameters that are missing, or one of the parameters is invalid.
   68 Please check the response `errors` key, and double-check the examples below for any discrepancies.
   69 
   70 ##### **404** Not Found
   71 
   72 The resource you are trying to access does not exist. This may also be returned if you attempt to access a private resource that you don't have authorization to view.
   73 
   74 ##### **422** Unprocessable Entity
   75 
   76 ##### **429** Too Many Requests
   77 
   78 You are currently being rate-limited. Please decrease your frequency of usage, or contact us at [support+vagrantcloud@hashicorp.com](mailto:support+vagrantcloud@hashicorp.com) with a description of your use case so that we can consider creating an exception.
   79 
   80 #### Server Errors
   81 
   82 ##### **500** Internal Server Error
   83 
   84 The server failed to respond to the request for an unknown reason.
   85 Please contact [support+vagrantcloud@hashicorp.com](mailto:support+vagrantcloud@hashicorp.com) with a description of the problem so that we can investigate.
   86 
   87 ##### **503** Service Unavailable
   88 
   89 Vagrant Cloud is temporarily in maintenance mode.
   90 Please check the [HashiCorp Status Site](http://status.hashicorp.com) for more information.
   91 
   92 ## Creating a usable box from scratch
   93 
   94 -> This assumes that you have a valid Vagrant Cloud authentication token. You can [create one via the API](#create-a-token), or [create one on the Vagrant Cloud website](https://app.vagrantup.com/settings/security).
   95 
   96 In order to create a usable box on Vagrant Cloud, perform the following steps:
   97 
   98 1. [Create a new box](#create-a-box)
   99 1. [Create a new version](#create-a-version)
  100 1. [Create a new provider](#create-a-provider)
  101 1. [Upload a box image for that provider](#upload-a-provider)
  102 1. [Release the version](#release-a-version)
  103 
  104 #### Example Requests
  105 
  106 <Tabs>
  107 <Tab heading="cURL">
  108 
  109 ```shell
  110 # Create a new box
  111 curl \
  112   --header "Content-Type: application/json" \
  113   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  114   https://app.vagrantup.com/api/v1/boxes \
  115   --data '{ "box": { "username": "myuser", "name": "test" } }'
  116 
  117 # Create a new version
  118 
  119 curl \
  120   --header "Content-Type: application/json" \
  121   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  122   https://app.vagrantup.com/api/v1/box/myuser/test/versions \
  123   --data '{ "version": { "version": "1.2.3" } }'
  124 
  125 # Create a new provider
  126 
  127 curl \
  128   --header "Content-Type: application/json" \
  129   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  130   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/providers \
  131   --data '{ "provider": { "name": "virtualbox" } }'
  132 
  133 # Prepare the provider for upload/get an upload URL
  134 
  135 response=$(curl \
  136     --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  137  https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox/upload)
  138 
  139 # Extract the upload URL from the response (requires the jq command)
  140 
  141 upload_path=$(echo "$response" | jq .upload_path)
  142 
  143 # Perform the upload
  144 
  145 curl $upload_path --request PUT --upload-file virtualbox-1.2.3.box
  146 
  147 # Release the version
  148 
  149 curl \
  150   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  151   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/release \
  152   --request PUT
  153 
  154 ```
  155 
  156 </Tab>
  157 <Tab heading="Ruby">
  158 
  159 ```ruby
  160 # gem install http, or add `gem "http"` to your Gemfile
  161 require "http"
  162 
  163 api = HTTP.persistent("https://app.vagrantup.com").headers(
  164   "Content-Type" => "application/json",
  165   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  166 )
  167 
  168 # Create a new box
  169 
  170 api.post "/api/v1/boxes",
  171 json: { box: { username: "myuser", name: "test" } }
  172 
  173 # Create a new version
  174 
  175 api.post "/api/v1/box/myuser/test/versions",
  176 json: { version: { version: "1.2.3" } }
  177 
  178 # Create a new provider
  179 
  180 api.post "/api/v1/box/myuser/test/version/1.2.3/providers",
  181 json: { provider: { name: "virtualbox" } }
  182 
  183 # Prepare the provider for upload
  184 
  185 response = api.get("/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox/upload")
  186 
  187 # Extract the upload URL
  188 
  189 upload_path = response.parse['upload_path']
  190 
  191 # Upload the box image
  192 
  193 HTTP.put upload_path, body: File.open("virtualbox-1.2.3.box")
  194 
  195 # Release the version
  196 
  197 api.put("/api/v1/box/myuser/test/version/1.2.3/release")
  198 ```
  199 
  200 </Tab>
  201 </Tabs>
  202 
  203 ## Authentication
  204 
  205 ### Create a token
  206 
  207 `POST /api/v1/authenticate`
  208 
  209 Creates a new token for the given user.
  210 
  211 #### Arguments
  212 
  213 - `token`
  214 - `description` (Optional) - A description of the token.
  215 - `two_factor`
  216 - `code` - A two-factor authentication code. Required to use this API method if 2FA is enabled. See [Request a 2FA code](#request-a-2fa-code) if not using a TOTP application.
  217 - `user`
  218 - `login` - Username or email address of the user authenticating.
  219 - `password` - The user's password.
  220 
  221 #### Example Request
  222 
  223 <Tabs>
  224 
  225 <Tab heading='cURL'>
  226 
  227 ```shell
  228 curl \
  229   --header "Content-Type: application/json" \
  230   https://app.vagrantup.com/api/v1/authenticate \
  231   --data '
  232     {
  233       "token": {
  234         "description": "Login from cURL"
  235       },
  236       "user": {
  237         "login": "myuser",
  238         "password": "secretpassword"
  239       }
  240     }
  241   '
  242 ```
  243 
  244 </Tab>
  245 <Tab heading='Ruby'>
  246 
  247 ```ruby
  248 # gem install http, or add `gem "http"` to your Gemfile
  249 require "http"
  250 
  251 api = HTTP.persistent("https://app.vagrantup.com").headers(
  252 "Content-Type" => "application/json"
  253 )
  254 
  255 response = api.post("/api/v1/authenticate", json: {
  256   token: { description: "Login from Ruby" },
  257   user: { login: "myuser", password: "secretpassword" }
  258 })
  259 
  260 if response.status.success? # Success, the response attributes are available here.
  261   p response.parse
  262 else # Error, inspect the `errors` key for more information.
  263   p response.code, response.body
  264 end
  265 ```
  266 
  267 </Tab>
  268 </Tabs>
  269 
  270 #### Example Response
  271 
  272 ```json
  273 {
  274   "description": "Login from cURL",
  275   "token": "qwlIE1qBVUafsg.atlasv1.FLwfJSSYkl49i4qZIu8R31GBnI9r8DrW4IQKMppkGq5rD264lRksTqaIN0zY9Bmy0zs",
  276   "token_hash": "7598236a879ecb42cb0f25399d6f25d1d2cfbbc6333392131bbdfba325eb352795c169daa4a61a8094d44afe817a857e0e5fc7dc72a1401eb434577337d1246c",
  277   "created_at": "2017-10-18T19:16:24.956Z"
  278 }
  279 ```
  280 
  281 ### Validate a token
  282 
  283 `GET /api/v1/authenticate`
  284 
  285 Responds [`200 OK`](#200-ok) if the authentication request was successful, otherwise responds [`401 Unauthorized`](#401-unauthorized).
  286 
  287 #### Example Request
  288 
  289 <Tabs>
  290 <Tab heading="cURL">
  291 
  292 ```shell
  293 curl \
  294   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  295   https://app.vagrantup.com/api/v1/authenticate
  296 ```
  297 
  298 </Tab>
  299 <Tab heading="Ruby">
  300 
  301 ```ruby
  302 # gem install http, or add `gem "http"` to your Gemfile
  303 require "http"
  304 
  305 api = HTTP.persistent("https://app.vagrantup.com").headers(
  306   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  307 )
  308 
  309 response = api.get("/api/v1/authenticate")
  310 
  311 if response.status.success? # Success, the response attributes are available here.
  312   p response.parse
  313 else # Error, inspect the `errors` key for more information.
  314   p response.code, response.body
  315 end
  316 ```
  317 
  318 </Tab>
  319 </Tabs>
  320 
  321 ### Delete a token
  322 
  323 `DELETE /api/v1/authenticate`
  324 
  325 Responds [`204 OK`](#204-no-content) if the deletion request was successful, otherwise responds [`401 Unauthorized`](#401-unauthorized).
  326 
  327 #### Example Request
  328 
  329 <Tabs>
  330 <Tab heading="cURL">
  331 
  332 ```shell
  333 curl \
  334   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  335   --request DELETE \
  336   https://app.vagrantup.com/api/v1/authenticate
  337 ```
  338 
  339 </Tab>
  340 <Tab heading="Ruby">
  341 
  342 ```ruby
  343 # gem install http, or add `gem "http"` to your Gemfile
  344 require "http"
  345 
  346 api = HTTP.persistent("https://app.vagrantup.com").headers(
  347   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  348 )
  349 
  350 response = api.delete("/api/v1/authenticate")
  351 
  352 if response.status.success? # Success, the response attributes are available here.
  353   p response.parse
  354 else # Error, inspect the `errors` key for more information.
  355   p response.code, response.body
  356 end
  357 ```
  358 
  359 </Tab>
  360 </Tabs>
  361 
  362 ### Request a 2FA code
  363 
  364 `POST /api/v1/two-factor/request-code`
  365 
  366 Sends a 2FA code to the requested delivery method.
  367 
  368 #### Arguments
  369 
  370 - `two_factor`
  371 - `delivery_method` - A valid 2FA delivery method. Currently only `sms` is supported.
  372 - `user`
  373 - `login` - Username or email address of the user authenticating.
  374 - `password` - The user's password.
  375 
  376 #### Example Request
  377 
  378 <Tabs>
  379 <Tab heading="cURL">
  380 
  381 ```shell
  382 curl \
  383   --header "Content-Type: application/json" \
  384   https://app.vagrantup.com/api/v1/authenticate \
  385   --data '
  386     {
  387       "two_factor": {
  388         "delivery_method": "sms"
  389       },
  390       "user": {
  391         "login": "myuser",
  392         "password": "secretpassword"
  393       }
  394     }
  395   '
  396 ```
  397 
  398 </Tab>
  399 <Tab heading="Ruby">
  400 
  401 ```ruby
  402 # gem install http, or add `gem "http"` to your Gemfile
  403 require "http"
  404 
  405 api = HTTP.persistent("https://app.vagrantup.com").headers(
  406   "Content-Type" => "application/json"
  407 )
  408 
  409 response = api.post("/api/v1/two-factor/request-code", json: {
  410   two_factor: { delivery_method: "sms" },
  411   user: { login: "myuser", password: "secretpassword" }
  412 })
  413 
  414 if response.status.success? # Success, the response attributes are available here.
  415   p response.parse
  416 else # Error, inspect the `errors` key for more information.
  417   p response.code, response.body
  418 end
  419 ```
  420 
  421 </Tab>
  422 </Tabs>
  423 
  424 #### Example Response
  425 
  426 ```json
  427 {
  428   "two_factor": {
  429     "obfuscated_destination": "SMS number ending in 7890"
  430   }
  431 }
  432 ```
  433 
  434 ## Organizations
  435 
  436 ### Read an organization
  437 
  438 `GET /api/v1/user/:username`
  439 
  440 #### Example Request
  441 
  442 <Tabs>
  443 <Tab heading="cURL">
  444 
  445 ```shell
  446 curl \
  447   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  448   https://app.vagrantup.com/api/v1/user/myuser
  449 ```
  450 
  451 </Tab>
  452 <Tab heading="Ruby">
  453 
  454 ```ruby
  455 # gem install http, or add `gem "http"` to your Gemfile
  456 require "http"
  457 
  458 api = HTTP.persistent("https://app.vagrantup.com").headers(
  459   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  460 )
  461 
  462 response = api.get("/api/v1/user/myuser")
  463 
  464 if response.status.success?
  465   # Success, the response attributes are available here.
  466   p response.parse
  467 else
  468   # Error, inspect the `errors` key for more information.
  469   p response.code, response.body
  470 end
  471 ```
  472 
  473 </Tab>
  474 </Tabs>
  475 
  476 #### Example Response
  477 
  478 ```json
  479 {
  480   "username": "myuser",
  481   "avatar_url": "https://www.gravatar.com/avatar/130a640278870c3dada38b3d912ee022?s=460&d=mm",
  482   "profile_html": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>\n",
  483   "profile_markdown": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
  484   "boxes": []
  485 }
  486 ```
  487 
  488 ## Search
  489 
  490 ### Search for boxes
  491 
  492 `GET /api/v1/search`
  493 
  494 #### Arguments
  495 
  496 - `q` - (Optional) The search query. Results will match the `username`, `name`, or `short_description` fields for a box. If omitted, the top boxes based on `sort` and `order` will be returned (defaults to "downloads desc").
  497 - `provider` - (Optional) Filter results to boxes supporting for a specific provider.
  498 - `sort` - (Optional, default: `"downloads"`) The field to sort results on. Can be one of `"downloads"`, `"created"`, or `"updated"`.
  499 - `order` - (Optional, default: `"desc"`) The order to return the sorted field in. Can be `"desc"` os `"asc"`.
  500 - `limit` - (Optional, default: `10`) The number of results to return (max of 100).
  501 - `page` - (Optional, default: `1`)
  502 
  503 #### Example Request
  504 
  505 <Tabs>
  506 <Tab heading="cURL">
  507 
  508 ```shell
  509 curl \
  510   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  511   https://app.vagrantup.com/api/v1/search?q=test&provider=virtualbox
  512 ```
  513 
  514 </Tab>
  515 <Tab heading="Ruby">
  516 
  517 ```ruby
  518 # gem install http, or add `gem "http"` to your Gemfile
  519 require "http"
  520 
  521 api = HTTP.persistent("https://app.vagrantup.com").headers(
  522   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  523 )
  524 
  525 response = api.get("/api/v1/search", params: {
  526   q: "test",
  527   provider: "virtualbox"
  528 })
  529 
  530 if response.status.success?
  531   # Success, the response attributes are available here.
  532   p response.parse
  533 else
  534   # Error, inspect the `errors` key for more information.
  535   p response.code, response.body
  536 end
  537 ```
  538 
  539 </Tab>
  540 </Tabs>
  541 
  542 #### Example Response
  543 
  544 ```json
  545 {
  546   "boxes": [
  547     {
  548       "created_at": "2017-10-20T14:19:59.842Z",
  549       "updated_at": "2017-10-20T15:23:53.363Z",
  550       "tag": "myuser/test",
  551       "name": "test",
  552       "short_description": "My dev box",
  553       "description_html": "<p>My development Vagrant box</p>\n",
  554       "username": "myuser",
  555       "description_markdown": "My development Vagrant box",
  556       "private": true,
  557       "downloads": 123,
  558       "current_version": {
  559         "version": "1.2.3",
  560         "status": "active",
  561         "description_html": "<p>A new version</p>\n",
  562         "description_markdown": "A new version",
  563         "created_at": "2017-10-20T15:23:17.184Z",
  564         "updated_at": "2017-10-20T15:23:53.355Z",
  565         "number": "1.2.3",
  566         "release_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/release",
  567         "revoke_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/revoke",
  568         "providers": [
  569           {
  570             "name": "virtualbox",
  571             "hosted": false,
  572             "hosted_token": null,
  573             "original_url": "https://example.com/virtualbox-1.2.3.box",
  574             "created_at": "2017-10-20T15:23:35.718Z",
  575             "updated_at": "2017-10-20T15:23:35.718Z",
  576             "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box"
  577           }
  578         ]
  579       }
  580     }
  581   ]
  582 }
  583 ```
  584 
  585 ## Boxes
  586 
  587 ### Read a box
  588 
  589 `GET /api/v1/box/:username/:name`
  590 
  591 #### Example Request
  592 
  593 <Tabs>
  594 <Tab heading="cURL">
  595 
  596 ```shell
  597 curl \
  598   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  599   https://app.vagrantup.com/api/v1/box/myuser/test
  600 ```
  601 
  602 </Tab>
  603 <Tab heading="Ruby">
  604 
  605 ```ruby
  606 # gem install http, or add `gem "http"` to your Gemfile
  607 require "http"
  608 
  609 api = HTTP.persistent("https://app.vagrantup.com").headers(
  610   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  611 )
  612 
  613 response = api.get("/api/v1/box/myuser/test")
  614 
  615 if response.status.success? # Success, the response attributes are available here.
  616   p response.parse
  617 else # Error, inspect the `errors` key for more information.
  618   p response.code, response.body
  619 end
  620 ```
  621 
  622 </Tab>
  623 </Tabs>
  624 
  625 #### Example Response
  626 
  627 ```json
  628 {
  629   "created_at": "2017-10-20T14:19:59.842Z",
  630   "updated_at": "2017-10-20T15:23:53.363Z",
  631   "tag": "myuser/test",
  632   "name": "test",
  633   "short_description": "My dev box",
  634   "description_html": "<p>My development Vagrant box</p>\n",
  635   "username": "myuser",
  636   "description_markdown": "My development Vagrant box",
  637   "private": true,
  638   "downloads": 123,
  639   "current_version": {
  640     "version": "1.2.3",
  641     "status": "active",
  642     "description_html": "<p>A new version</p>\n",
  643     "description_markdown": "A new version",
  644     "created_at": "2017-10-20T15:23:17.184Z",
  645     "updated_at": "2017-10-20T15:23:53.355Z",
  646     "number": "1.2.3",
  647     "release_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/release",
  648     "revoke_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/revoke",
  649     "providers": [
  650       {
  651         "name": "virtualbox",
  652         "hosted": false,
  653         "hosted_token": null,
  654         "original_url": "https://example.com/virtualbox-1.2.3.box",
  655         "created_at": "2017-10-20T15:23:35.718Z",
  656         "updated_at": "2017-10-20T15:23:35.718Z",
  657         "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box"
  658       }
  659     ]
  660   },
  661   "versions": [
  662     {
  663       "version": "1.2.3",
  664       "status": "active",
  665       "description_html": "<p>A new version</p>\n",
  666       "description_markdown": "A new version",
  667       "created_at": "2017-10-20T15:23:17.184Z",
  668       "updated_at": "2017-10-20T15:23:53.355Z",
  669       "number": "1.2.3",
  670       "release_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/release",
  671       "revoke_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/revoke",
  672       "providers": [
  673         {
  674           "name": "virtualbox",
  675           "hosted": false,
  676           "hosted_token": null,
  677           "original_url": "https://example.com/virtualbox-1.2.3.box",
  678           "created_at": "2017-10-20T15:23:35.718Z",
  679           "updated_at": "2017-10-20T15:23:35.718Z",
  680           "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box"
  681         }
  682       ]
  683     }
  684   ]
  685 }
  686 ```
  687 
  688 ### Create a box
  689 
  690 `POST /api/v1/boxes`
  691 
  692 #### Arguments
  693 
  694 - `box`
  695   - `username` - The username of the organization that will own this box.
  696   - `name` - The name of the box.
  697   - `short_description` - A short summary of the box.
  698   - `description` - A longer description of the box. Can be formatted with [Markdown][markdown].
  699   - `is_private` (Optional, default: `true`) - Whether or not this box is private.
  700 
  701 #### Example Request
  702 
  703 <Tabs>
  704 <Tab heading="cURL">
  705 
  706 ```shell
  707 curl \
  708   --header "Content-Type: application/json" \
  709   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  710   https://app.vagrantup.com/api/v1/boxes \
  711   --data '
  712     {
  713       "box": {
  714         "username": "myuser",
  715         "name": "test",
  716         "short_description": "My dev box",
  717         "description": "My development Vagrant box",
  718         "is_private": true
  719       }
  720     }
  721   '
  722 ```
  723 
  724 </Tab>
  725 <Tab heading="Ruby">
  726 
  727 ```ruby
  728 # gem install http, or add `gem "http"` to your Gemfile
  729 require "http"
  730 
  731 api = HTTP.persistent("https://app.vagrantup.com").headers(
  732   "Content-Type" => "application/json",
  733   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  734 )
  735 
  736 response = api.post("/api/v1/boxes", json: {
  737   box: {
  738     username: "myuser",
  739     name: "test",
  740     short_description: "My dev box",
  741     description: "My development Vagrant box",
  742     is_private: true
  743   }
  744 })
  745 
  746 if response.status.success?
  747   # Success, the response attributes are available here.
  748   p response.parse
  749 else
  750   # Error, inspect the `errors` key for more information.
  751   p response.code, response.body
  752 end
  753 ```
  754 
  755 </Tab>
  756 </Tabs>
  757 
  758 #### Example Response
  759 
  760 Response body is identical to [Reading a box](#read-a-box).
  761 
  762 ### Update a box
  763 
  764 `PUT /api/v1/box/:username/:name`
  765 
  766 #### Arguments
  767 
  768 - `box`
  769   - `name` - The name of the box.
  770   - `short_description` - A short summary of the box.
  771   - `description` - A longer description of the box. Can be formatted with [Markdown](https://daringfireball.net/projects/markdown/syntax).
  772   - `is_private` (Optional, default: `true`) - Whether or not this box is private.
  773 
  774 #### Example Request
  775 
  776 <Tabs>
  777 <Tab heading="cURL">
  778 
  779 ```shell
  780 curl \
  781   --header "Content-Type: application/json" \
  782   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  783   https://app.vagrantup.com/api/v1/box/myuser/test \
  784   --request PUT \
  785   --data '
  786     {
  787       "box": {
  788         "name": "test",
  789         "short_description": "My dev box",
  790         "description": "My development Vagrant box",
  791         "is_private": true
  792       }
  793     }
  794   '
  795 ```
  796 
  797 </Tab>
  798 <Tab heading="Ruby">
  799 
  800 ```ruby
  801 # gem install http, or add `gem "http"` to your Gemfile
  802 require "http"
  803 
  804 api = HTTP.persistent("https://app.vagrantup.com").headers(
  805   "Content-Type" => "application/json",
  806   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  807 )
  808 
  809 response = api.put("/api/v1/box/myuser/test", json: {
  810   box: {
  811     name: "test",
  812     short_description: "My dev box",
  813     description: "My development Vagrant box",
  814     is_private: true
  815   }
  816 })
  817 
  818 if response.status.success?
  819   # Success, the response attributes are available here.
  820   p response.parse
  821 else
  822   # Error, inspect the `errors` key for more information.
  823   p response.code, response.body
  824 end
  825 ```
  826 
  827 </Tab>
  828 </Tabs>
  829 
  830 ### Delete a box
  831 
  832 `DELETE /api/v1/box/:username/:name`
  833 
  834 #### Example Request
  835 
  836 <Tabs>
  837 <Tab heading="cURL">
  838 
  839 ```shell
  840 curl \
  841   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  842   --request DELETE \
  843   https://app.vagrantup.com/api/v1/box/myuser/test
  844 ```
  845 
  846 </Tab>
  847 <Tab heading="Ruby">
  848 
  849 ```ruby
  850 # gem install http, or add `gem "http"` to your Gemfile
  851 require "http"
  852 
  853 api = HTTP.persistent("https://app.vagrantup.com").headers(
  854   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  855 )
  856 
  857 response = api.delete("/api/v1/box/myuser/test")
  858 
  859 if response.status.success?
  860   # Success, the response attributes are available here.
  861   p response.parse
  862 else
  863   # Error, inspect the `errors` key for more information.
  864   p response.code, response.body
  865 end
  866 ```
  867 
  868 </Tab>
  869 </Tabs>
  870 
  871 #### Example Response
  872 
  873 Response body is identical to [Reading a box](#read-a-box).
  874 
  875 ## Versions
  876 
  877 ### Read a version
  878 
  879 `GET /api/v1/box/:username/:name/version/:version`
  880 
  881 #### Example Request
  882 
  883 <Tabs>
  884 <Tab heading="cURL">
  885 
  886 ```shell
  887 curl \
  888   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  889   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3
  890 ```
  891 
  892 </Tab>
  893 <Tab heading="Ruby">
  894 
  895 ```ruby
  896 # gem install http, or add `gem "http"` to your Gemfile
  897 require "http"
  898 
  899 api = HTTP.persistent("https://app.vagrantup.com").headers(
  900   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  901 )
  902 
  903 response = api.get("/api/v1/box/myuser/test/version/1.2.3")
  904 
  905 if response.status.success?
  906   # Success, the response attributes are available here.
  907   p response.parse
  908 else
  909   # Error, inspect the `errors` key for more information.
  910   p response.code, response.body
  911 end
  912 ```
  913 
  914 </Tab>
  915 </Tabs>
  916 
  917 #### Example Response
  918 
  919 ```json
  920 {
  921   "version": "1.2.3",
  922   "status": "active",
  923   "description_html": "<p>A new version</p>\n",
  924   "description_markdown": "A new version",
  925   "created_at": "2017-10-20T15:23:17.184Z",
  926   "updated_at": "2017-10-20T15:23:53.355Z",
  927   "number": "1.2.3",
  928   "release_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/release",
  929   "revoke_url": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/revoke",
  930   "providers": [
  931     {
  932       "name": "virtualbox",
  933       "hosted": false,
  934       "hosted_token": null,
  935       "original_url": "https://example.com/virtualbox-1.2.3.box",
  936       "created_at": "2017-10-20T15:23:35.718Z",
  937       "updated_at": "2017-10-20T15:23:35.718Z",
  938       "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box"
  939     }
  940   ]
  941 }
  942 ```
  943 
  944 ### Create a version
  945 
  946 `POST /api/v1/box/:username/:name/versions`
  947 
  948 -> New versions start as `unreleased`. You must create a valid provider before releasing a new version.
  949 
  950 #### Arguments
  951 
  952 - `version`
  953   - `version` - The version number of this version.
  954   - `description` - A description for this version. Can be formatted with [Markdown](https://daringfireball.net/projects/markdown/syntax).
  955 
  956 #### Example Request
  957 
  958 <Tabs>
  959 <Tab heading="cURL">
  960 
  961 ```shell
  962 curl \
  963   --header "Content-Type: application/json" \
  964   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
  965   https://app.vagrantup.com/api/v1/box/myuser/test/versions \
  966   --data '
  967     {
  968       "version": {
  969         "version": "1.2.3",
  970         "description": "A new version"
  971       }
  972     }
  973   '
  974 ```
  975 
  976 </Tab>
  977 <Tab heading="Ruby">
  978 
  979 ```ruby
  980 # gem install http, or add `gem "http"` to your Gemfile
  981 require "http"
  982 
  983 api = HTTP.persistent("https://app.vagrantup.com").headers(
  984   "Content-Type" => "application/json",
  985   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
  986 )
  987 
  988 response = api.post("/api/v1/box/myuser/test/versions", json: {
  989   version: {
  990     version: "1.2.3",
  991     description: "A new version"
  992   }
  993 })
  994 
  995 if response.status.success?
  996   # Success, the response attributes are available here.
  997   p response.parse
  998 else
  999   # Error, inspect the `errors` key for more information.
 1000   p response.code, response.body
 1001 end
 1002 ```
 1003 
 1004 </Tab>
 1005 </Tabs>
 1006 
 1007 #### Example Response
 1008 
 1009 Response body is identical to [Reading a version](#read-a-version).
 1010 
 1011 ### Update a version
 1012 
 1013 `PUT /api/v1/box/:username/:name/version/1.2.3`
 1014 
 1015 #### Arguments
 1016 
 1017 - `version`
 1018   - `version` - The version number of this version.
 1019   - `description` - A description for this version. Can be formatted with [Markdown][markdown].
 1020 
 1021 #### Example Request
 1022 
 1023 <Tabs>
 1024 <Tab heading="cURL">
 1025 
 1026 ```shell
 1027 curl \
 1028   --header "Content-Type: application/json" \
 1029   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1030   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3 \
 1031   --request PUT \
 1032   --data '
 1033     {
 1034       "version": {
 1035         "version": "1.2.3",
 1036         "description": "A new version"
 1037       }
 1038     }
 1039   '
 1040 ```
 1041 
 1042 </Tab>
 1043 <Tab heading="Ruby">
 1044 
 1045 ```ruby
 1046 # gem install http, or add `gem "http"` to your Gemfile
 1047 require "http"
 1048 
 1049 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1050   "Content-Type" => "application/json",
 1051   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1052 )
 1053 
 1054 response = api.put("/api/v1/box/myuser/test/version/1.2.3", json: {
 1055   version: {
 1056     name: "1.2.3",
 1057     description: "A new version"
 1058   }
 1059 })
 1060 
 1061 if response.status.success?
 1062   # Success, the response attributes are available here.
 1063   p response.parse
 1064 else
 1065   # Error, inspect the `errors` key for more information.
 1066   p response.code, response.body
 1067 end
 1068 ```
 1069 
 1070 </Tab>
 1071 </Tabs>
 1072 
 1073 #### Example Response
 1074 
 1075 Response body is identical to [Reading a version](#read-a-version).
 1076 
 1077 ### Delete a version
 1078 
 1079 `DELETE /api/v1/box/:username/:name/version/:version`
 1080 
 1081 #### Example Request
 1082 
 1083 <Tabs>
 1084 <Tab heading="cURL">
 1085 
 1086 ```shell
 1087 curl \
 1088   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1089   --request DELETE \
 1090   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3
 1091 ```
 1092 
 1093 </Tab>
 1094 <Tab heading="Ruby">
 1095 
 1096 ```ruby
 1097 # gem install http, or add `gem "http"` to your Gemfile
 1098 require "http"
 1099 
 1100 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1101   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1102 )
 1103 
 1104 response = api.delete("/api/v1/box/myuser/test/version/1.2.3")
 1105 
 1106 if response.status.success?
 1107   # Success, the response attributes are available here.
 1108   p response.parse
 1109 else
 1110   # Error, inspect the `errors` key for more information.
 1111   p response.code, response.body
 1112 end
 1113 ```
 1114 
 1115 </Tab>
 1116 </Tabs>
 1117 
 1118 #### Example Response
 1119 
 1120 Response body is identical to [Reading a version](#read-a-version).
 1121 
 1122 ### Release a version
 1123 
 1124 `PUT /api/v1/box/:username/:name/version/1.2.3/release`
 1125 
 1126 #### Example Request
 1127 
 1128 <Tabs>
 1129 <Tab heading="cURL">
 1130 
 1131 ```shell
 1132 curl \
 1133   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1134   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/release \
 1135   --request PUT
 1136 ```
 1137 
 1138 </Tab>
 1139 <Tab heading="Ruby">
 1140 
 1141 ```ruby
 1142 # gem install http, or add `gem "http"` to your Gemfile
 1143 require "http"
 1144 
 1145 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1146   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1147 )
 1148 
 1149 response = api.put("/api/v1/box/myuser/test/version/1.2.3/release")
 1150 
 1151 if response.status.success?
 1152   # Success, the response attributes are available here.
 1153   p response.parse
 1154 else
 1155   # Error, inspect the `errors` key for more information.
 1156   p response.code, response.body
 1157 end
 1158 ```
 1159 
 1160 </Tab>
 1161 </Tabs>
 1162 
 1163 #### Example Response
 1164 
 1165 Response body is identical to [Reading a version](#read-a-version).
 1166 
 1167 ### Revoke a version
 1168 
 1169 `PUT /api/v1/box/:username/:name/version/1.2.3/revoke`
 1170 
 1171 #### Example Request
 1172 
 1173 <Tabs>
 1174 <Tab heading="cURL">
 1175 
 1176 ```shell
 1177 curl \
 1178   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1179   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/revoke \
 1180   --request PUT
 1181 ```
 1182 
 1183 </Tab>
 1184 <Tab heading="Ruby">
 1185 
 1186 ```ruby
 1187 # gem install http, or add `gem "http"` to your Gemfile
 1188 require "http"
 1189 
 1190 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1191   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1192 )
 1193 
 1194 response = api.put("/api/v1/box/myuser/test/version/1.2.3/revoke")
 1195 
 1196 if response.status.success?
 1197   # Success, the response attributes are available here.
 1198   p response.parse
 1199 else
 1200   # Error, inspect the `errors` key for more information.
 1201   p response.code, response.body
 1202 end
 1203 ```
 1204 
 1205 </Tab>
 1206 </Tabs>
 1207 
 1208 #### Example Response
 1209 
 1210 Response body is identical to [Reading a version](#read-a-version).
 1211 
 1212 ## Providers
 1213 
 1214 ### Read a provider
 1215 
 1216 `GET /api/v1/box/:username/:name/version/:version/provider/:provider`
 1217 
 1218 #### Example Request
 1219 
 1220 <Tabs>
 1221 <Tab heading="cURL">
 1222 
 1223 ```shell
 1224 curl \
 1225   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1226   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox
 1227 ```
 1228 
 1229 </Tab>
 1230 <Tab heading="Ruby">
 1231 
 1232 ```ruby
 1233 # gem install http, or add `gem "http"` to your Gemfile
 1234 require "http"
 1235 
 1236 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1237   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1238 )
 1239 
 1240 response = api.get("/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox")
 1241 
 1242 if response.status.success?
 1243   # Success, the response attributes are available here.
 1244   p response.parse
 1245 else
 1246   # Error, inspect the `errors` key for more information.
 1247   p response.code, response.body
 1248 end
 1249 ```
 1250 
 1251 </Tab>
 1252 </Tabs>
 1253 
 1254 #### Example Response
 1255 
 1256 ```json
 1257 {
 1258   "name": "virtualbox",
 1259   "hosted": false,
 1260   "hosted_token": null,
 1261   "original_url": "https://example.com/virtualbox-1.2.3.box",
 1262   "created_at": "2017-10-20T15:23:35.718Z",
 1263   "updated_at": "2017-10-20T15:23:35.718Z",
 1264   "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box",
 1265   "checksum": "a59e7332e8bbe896f11f478fc61fa8a6",
 1266   "checksum_type": "md5"
 1267 }
 1268 ```
 1269 
 1270 ### Create a provider
 1271 
 1272 `POST /api/v1/box/:username/:name/version/:version/providers`
 1273 
 1274 #### Arguments
 1275 
 1276 - `provider`
 1277   - `name` - The name of the provider.
 1278   - `url` - A valid URL to download this provider. If omitted, you must [upload](#upload-a-provider) the Vagrant box image for this provider to Vagrant Cloud before the provider can be used.
 1279   - `checksum` - Computed checksum of the box assets. When set, Vagrant will compute the checksum of the downloaded box asset and validate it matches this value.
 1280   - `checksum_type` - Type of checksum used. Currently supported values: md5, sha1, sha256, sha384, and sha512
 1281 
 1282 #### Example Request
 1283 
 1284 <Tabs>
 1285 <Tab heading="cURL">
 1286 
 1287 ```shell
 1288 curl \
 1289   --header "Content-Type: application/json" \
 1290   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1291   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/providers \
 1292   --data '
 1293     {
 1294       "provider": {
 1295         "checksum": "a59e7332e8bbe896f11f478fc61fa8a6",
 1296         "checksum_type": "md5",
 1297         "name": "virtualbox",
 1298         "url": "https://example.com/virtualbox-1.2.3.box"
 1299       }
 1300     }
 1301   '
 1302 ```
 1303 
 1304 </Tab>
 1305 <Tab heading="Ruby">
 1306 
 1307 ```ruby
 1308 # gem install http, or add `gem "http"` to your Gemfile
 1309 require "http"
 1310 
 1311 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1312   "Content-Type" => "application/json",
 1313   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1314 )
 1315 
 1316 response = api.post("/api/v1/box/myuser/test/version/1.2.3/providers", json: {
 1317   provider: {
 1318     name: "virtualbox",
 1319     url: "https://example.com/virtualbox-1.2.3.box"
 1320   }
 1321 })
 1322 
 1323 if response.status.success?
 1324   # Success, the response attributes are available here.
 1325   p response.parse
 1326 else
 1327   # Error, inspect the `errors` key for more information.
 1328   p response.code, response.body
 1329 end
 1330 ```
 1331 
 1332 </Tab>
 1333 </Tabs>
 1334 
 1335 #### Example Response
 1336 
 1337 Response body is identical to [Reading a provider](#read-a-provider).
 1338 
 1339 ### Update a provider
 1340 
 1341 `PUT /api/v1/box/:username/:name/version/:version/provider/:provider`
 1342 
 1343 #### Arguments
 1344 
 1345 - `provider`
 1346   - `name` - The name of the provider.
 1347   - `url` - A valid URL to download this provider. If omitted, you must [upload](#upload-a-provider) the Vagrant box image for this provider to Vagrant Cloud before the provider can be used.
 1348 
 1349 #### Example Request
 1350 
 1351 <Tabs>
 1352 <Tab heading="cURL">
 1353 
 1354 ```shell
 1355 curl \
 1356   --header "Content-Type: application/json" \
 1357   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1358   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox \
 1359   --request PUT \
 1360   --data '
 1361     {
 1362       "provider": {
 1363         "checksum": "a59e7332e8bbe896f11f478fc61fa8a6",
 1364         "checksum_type": "md5",
 1365         "name": "virtualbox",
 1366         "url": "https://example.com/virtualbox-1.2.3.box"
 1367       }
 1368     }
 1369   '
 1370 ```
 1371 
 1372 </Tab>
 1373 <Tab heading="Ruby">
 1374 
 1375 ```ruby
 1376 # gem install http, or add `gem "http"` to your Gemfile
 1377 require "http"
 1378 
 1379 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1380   "Content-Type" => "application/json",
 1381   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1382 )
 1383 
 1384 response = api.put("/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox", json: {
 1385   provider: {
 1386     name: "virtualbox",
 1387     url: "https://example.com/virtualbox-1.2.3.box"
 1388   }
 1389 })
 1390 
 1391 if response.status.success?
 1392   # Success, the response attributes are available here.
 1393   p response.parse
 1394 else
 1395   # Error, inspect the `errors` key for more information.
 1396   p response.code, response.body
 1397 end
 1398 ```
 1399 
 1400 </Tab>
 1401 </Tabs>
 1402 
 1403 #### Example Response
 1404 
 1405 Response body is identical to [Reading a provider](#read-a-provider).
 1406 
 1407 ### Delete a provider
 1408 
 1409 `DELETE /api/v1/box/:username/:name/version/:version/provider/:provider`
 1410 
 1411 #### Example Request
 1412 
 1413 <Tabs>
 1414 <Tab heading="cURL">
 1415 
 1416 ```shell
 1417 curl \
 1418   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1419   --request DELETE \
 1420   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox
 1421 ```
 1422 
 1423 </Tab>
 1424 <Tab heading="Ruby">
 1425 
 1426 ```ruby
 1427 # gem install http, or add `gem "http"` to your Gemfile
 1428 require "http"
 1429 
 1430 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1431   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1432 )
 1433 
 1434 response = api.delete("/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox")
 1435 
 1436 if response.status.success?
 1437   # Success, the response attributes are available here.
 1438   p response.parse
 1439 else
 1440   # Error, inspect the `errors` key for more information.
 1441   p response.code, response.body
 1442 end
 1443 ```
 1444 
 1445 </Tab>
 1446 </Tabs>
 1447 
 1448 #### Example Response
 1449 
 1450 Response body is identical to [Reading a provider](#read-a-provider).
 1451 
 1452 ### Upload a provider
 1453 
 1454 `GET /api/v1/box/:username/:name/version/:version/provider/:provider/upload`
 1455 
 1456 Prepares the provider for upload, and returns a JSON blob containing an `upload_path`.
 1457 
 1458 ~> The upload must begin shortly after the response is returned, otherwise the URL will expire. If the URL expires, you can request this same API method again for a new upload URL.
 1459 
 1460 #### Example Request
 1461 
 1462 <Tabs>
 1463 <Tab heading="cURL">
 1464 
 1465 ```shell
 1466 response=$(curl \
 1467   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1468   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox/upload)
 1469 
 1470 # Requires the jq command
 1471 upload_path=$(echo "$response" | jq .upload_path)
 1472 
 1473 curl \
 1474   $upload_path \
 1475   --request PUT \
 1476   --upload-file virtualbox-1.2.3.box
 1477 ```
 1478 
 1479 </Tab>
 1480 <Tab heading="Ruby">
 1481 
 1482 ```ruby
 1483 # gem install http, or add `gem "http"` to your Gemfile
 1484 require "http"
 1485 
 1486 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1487   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1488 )
 1489 
 1490 response = api.get("/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox/upload")
 1491 
 1492 if response.status.success?
 1493   # Success, you can now upload the box image to the returned URL
 1494   upload_path = response.parse['upload_path']
 1495   HTTP.post upload_path, body: File.open("virtualbox-1.2.3.box")
 1496 else
 1497   # Error, inspect the `errors` key for more information.
 1498   p response.code, response.body
 1499 end
 1500 ```
 1501 
 1502 </Tab>
 1503 </Tabs>
 1504 
 1505 #### Example Response
 1506 
 1507 ```json
 1508 {
 1509   "upload_path": "https://archivist.hashicorp.com/v1/object/630e42d9-2364-2412-4121-18266770468e"
 1510 }
 1511 ```
 1512 
 1513 ### Upload a provider directly to backend storage
 1514 
 1515 `GET /api/v1/box/:username/:name/version/:version/provider/:provider/upload/direct`
 1516 
 1517 Prepares the provider for upload. This version of the upload API allows uploading the box asset directly to the backend storage. It requires
 1518 a two step process for uploading the box assets. First uploading the asset to storage and then finalizing the upload within Vagrant Cloud
 1519 via a provided callback.
 1520 
 1521 The request returns a JSON blob containing two fields:
 1522 
 1523 - `upload_path` - URL to `PUT` the box asset
 1524 - `callback` - Vagrant Cloud callback URL to finalize upload
 1525 
 1526 The box asset is uploaded directly to the URL provided by the `upload_path` via a `PUT` request. Once complete, a `PUT` request to the URL
 1527 provided in the `callback` field (complete with authentication header) finalizes the upload.
 1528 
 1529 ~> The upload must begin shortly after the response is returned, otherwise the URL will expire. If the URL expires, you can request this same API method again for a new upload URL.
 1530 
 1531 #### Example Request
 1532 
 1533 <Tabs>
 1534 <Tab heading="cURL">
 1535 
 1536 ```shell
 1537 response=$(curl \
 1538   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1539   https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox/upload/direct)
 1540 
 1541 # Requires the jq command
 1542 upload_path=$(echo "$response" | jq .upload_path)
 1543 callback=$(echo "$response" | jq .callback)
 1544 
 1545 curl \
 1546   "$upload_path" \
 1547   --request PUT \
 1548   --upload-file virtualbox-1.2.3.box
 1549 
 1550 curl
 1551   $callback \
 1552   --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \
 1553   --request PUT
 1554 ```
 1555 
 1556 </Tab>
 1557 <Tab heading="Ruby">
 1558 
 1559 ```ruby
 1560 # gem install http, or add `gem "http"` to your Gemfile
 1561 require "http"
 1562 require "uri"
 1563 
 1564 api = HTTP.persistent("https://app.vagrantup.com").headers(
 1565   "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}"
 1566 )
 1567 
 1568 response = api.get("/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox/upload")
 1569 
 1570 if response.status.success?
 1571   # Success, you can now upload the box image to the returned URL
 1572   upload_path = response.parse['upload_path']
 1573   callback = response.parse['callback']
 1574   # Upload the box asset
 1575   HTTP.post upload_path, body: File.open("virtualbox-1.2.3.box")
 1576   # Finalize the upload
 1577   api.put(URI.parse(callback).path)
 1578 else
 1579   # Error, inspect the `errors` key for more information.
 1580   p response.code, response.body
 1581 end
 1582 ```
 1583 
 1584 </Tab>
 1585 </Tabs>
 1586 
 1587 #### Example Response
 1588 
 1589 ```json
 1590 {
 1591   "upload_path": "https://remote-storage.example.com/bucket/630e42d9-2364-2412-4121-18266770468e?auth=9023wqfda",
 1592   "callback": "https://app.vagrantup.com/api/v1/box/myuser/test/version/1.2.3/provider/virtualbox/upload/direct/630e42d9-2364-2412-4121-18266770468e"
 1593 }
 1594 ```
 1595 
 1596 [markdown]: https://daringfireball.net/projects/markdown/syntax