> This page is for De cámara a la nube.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# Intercambio de token de dispositivo

POST https://api.frame.io/v2/auth/token
Content-Type: multipart/form-data

Punto final de token de OAuth 2.0 para la autorización de dispositivos. Admite varios tipos de concesión: sondeo para la autorización de dispositivos (device_code) y actualización de tokens (refresh_token).

Reference: https://next.developer.frame.io/camera-to-cloud/api-reference/authentication/auth-device-token

## Request

### Body (multipart/form-data)

This endpoint expects a multipart form.

- `client_id` (string, required) — Debe ser un identificador único por dispositivo de hardware, como un número de serie de hardware único. Debe ser el mismo que el ID de cliente que se ha utilizado en la autorización inicial.
- `client_secret` (string, required) — Una cadena estática proporcionada por Frame.io para incrustarla en un fabricante/modelo de dispositivos. Actúa como un identificador dentro de Frame.io.
- `grant_type` (enum, required) — Tipo de concesión: use 'urn:ietf:params:oauth:grant-type:device_code' para sondeo o 'refresh_token' para actualizar un token de acceso
- `device_code` (string, optional) — El código de dispositivo recibido del punto final /v2/auth/device/code. Obligatorio cuando grant_type es 'urn:ietf:params:oauth:grant-type:device_code'.
- `refresh_token` (string, optional) — Un refresh_token válido de una autorización anterior. Los tokens de actualización son válidos durante 14 días a partir de su emisión. Obligatorio cuando grant_type es 'refresh_token'.

## Response

### 200

Aceptar

## Examples

**Request**

```json
{}
```

**Response**

```json
{
  "access_token": "[access_token]",
  "expires_in": 28800,
  "refresh_token": "[refresh_token]",
  "token_type": "bearer"
}
```

**SDK Code**

```typescript
const formData = new FormData();
formData.append('grant_type', 'urn:ietf:params:oauth:grant-type:device_code');
formData.append('device_code', 'YOUR_DEVICE_CODE_FROM_STEP_1');
formData.append('client_id', 'YOUR_CLIENT_ID');
formData.append('client_secret', 'YOUR_CLIENT_SECRET');

const response = await fetch('https://api.frame.io/v2/auth/token', {
  method: 'POST',
  body: formData
});

const result = await response.json();
console.log(result);
```

```python
import requests

data = {
    'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
    'device_code': 'YOUR_DEVICE_CODE_FROM_STEP_1',
    'client_id': 'YOUR_CLIENT_ID',
    'client_secret': 'YOUR_CLIENT_SECRET'
}

response = requests.post(
    'https://api.frame.io/v2/auth/token',
    data=data
)

result = response.json()
print(result)
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.frame.io/v2/auth/token"

	payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"device_code\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"refresh_token\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.frame.io/v2/auth/token")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'multipart/form-data; boundary=---011000010111000001101001'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"device_code\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"refresh_token\"\r\n\r\n\r\n-----011000010111000001101001--\r\n"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.frame.io/v2/auth/token")
  .header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
  .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"device_code\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"refresh_token\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.frame.io/v2/auth/token', [
  'headers' => [
    'Content-Type' => 'multipart/form-data; boundary=---011000010111000001101001',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.frame.io/v2/auth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "multipart/form-data; boundary=---011000010111000001101001");
request.AddParameter("multipart/form-data; boundary=---011000010111000001101001", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"device_code\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"refresh_token\"\r\n\r\n\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Content-Type": "multipart/form-data; boundary=---011000010111000001101001"]
let parameters = [
  [
    "name": "client_id",
    "value": 
  ],
  [
    "name": "client_secret",
    "value": 
  ],
  [
    "name": "device_code",
    "value": 
  ],
  [
    "name": "grant_type",
    "value": 
  ],
  [
    "name": "refresh_token",
    "value": 
  ]
]

let boundary = "---011000010111000001101001"

var body = ""
var error: NSError? = nil
for param in parameters {
  let paramName = param["name"]!
  body += "--\(boundary)\r\n"
  body += "Content-Disposition:form-data; name=\"\(paramName)\""
  if let filename = param["fileName"] {
    let contentType = param["content-type"]!
    let fileContent = String(contentsOfFile: filename, encoding: String.Encoding.utf8)
    if (error != nil) {
      print(error as Any)
    }
    body += "; filename=\"\(filename)\"\r\n"
    body += "Content-Type: \(contentType)\r\n\r\n"
    body += fileContent
  } else if let paramValue = param["value"] {
    body += "\r\n\r\n\(paramValue)"
  }
}

let request = NSMutableURLRequest(url: NSURL(string: "https://api.frame.io/v2/auth/token")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```