The Flight Reader API is organized around REST. The API has predictable resource-oriented URLs, accepts multipart form data request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, Bearer authentication, and verbs.

Authentication
The Flight Reader API uses a Bearer token and optional request signing (required when using your public API key) to authenticate requests.

All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.

Do not share your secret API key in publicly accessible areas like GitHub or client-side code. Anyone who has access to your secret API key will be able to make API requests on your behalf.

TYPE VALUE WHEN TO USE
Secret sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Use this key on the server side. It must be kept secret and stored securely in your web or application's server-side code. Don't expose this key on a website or embed it in a client-side application.
Public pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Use this key on the client side. It can be exposed on website or in a client-side application. A request signature must be included in all requests using a public key.

Response Compression
By default, the Flight Reader API returns uncompressed responses. In order to reduce both the API response time and bandwidth consumption, you should include the Accept-Encoding header in all requests with a value of gzip (for Gzip compression) or br (for Brotli compression).

Errors
The Flight Reader API uses conventional HTTP response codes to indicate the success or failure of an API request. Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g. a required parameter was omitted). Codes in the 5xx range indicate an error with Flight Reader's servers.

The Flight Reader API raises exceptions for many reasons, such as invalid parameters, authentication errors, and network unavailability. You should ensure your code is able to gracefully handle all possible API exceptions.

Versioning
When backwards-incompatible changes are made to the API, a new version will be released released. For example, version 1 (the current version) is accessible at https://api.flightreader.com/v1. When version 2 is released, it will be available at https://api.flightreader.com/v2.

The following changes are considered to be backwards-compatible:
  • Adding a new API resource.
  • Adding a new optional request parameter to an existing API method.
  • Adding a new property to an existing API response.
  • Changing the order of properties in existing API responses.
  • Changing the length or format of strings in error messages, field descriptions, or other human-readable strings.

Resources
The following resources are available:
  • POST /v1/accounts/dji
    Retrieves a unique id for a DJI account. This unique id is used when retrieving a list of flight logs for a DJI account.

  • DELETE /v1/keys/{key}
    Delete a set of secret and public API keys.
  • GET /v1/keys
    Retrieves all active API keys.
  • POST /v1/keys
    Creates a new set of secret and public API keys.

  • GET /v1/fields
    Retrieves a list of all available flight log fields.
  • GET /v1/fields/{field-name}
    Retrieves a single flight log field by name.

  • POST /v1/logs
    Uploads a TXT flight log, processes it, and returns the flight log data in CSV format.
  • POST /v1/logs
    Processes a TXT flight log located at the specified URL and returns the flight log data in CSV format.
  • GET /v1/logs/{id}
    Retrieves a list of flight logs available in the DJI Cloud for a DJI account id.

  • GET /v1/usage
    Retrieve a list of API requests made by your API account.




Retrieve all flight log fields
Retrieves a list of all available flight log fields. These field names can be used to specify which fields to return when processing a flight log.

GET /v1/fields

                                <html>

                                <body>
                                    <div id="output">Retrieving log fields...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        async function retrieveLogFields() {
                                            try {
                                                const response = await fetch("https://api.flightreader.com/v1/fields", {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        retrieveLogFields();
                                    </script>
                                </body>

                                </html>
                            

                                <html>

                                <body>
                                    <!-- https://github.com/brix/crypto-js -->
                                    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

                                    <div id="output">Retrieving log fields...</div>

                                    <script>
                                        // Replace with your Flight Reader API keys
                                        const publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        async function retrieveLogFields() {
                                            try {
                                                // Create a request signature used by the Flight Reader API to verify the request was
                                                // initiated by you. This signature will expire 5 minutes after it's created.
                                                const signature = createSignature();

                                                const response = await fetch("https://api.flightreader.com/v1/fields", {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${publicApiKey}`,
                                                        "Api-Signature": signature.value,
                                                        "Api-Timestamp": signature.currentUnixTimeInSeconds
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        function createSignature() {
                                            const currentUnixTimeInSeconds = Math.floor(Date.now() / 1000);
                                            const requestMethod = "GET";
                                            const requestResource = "/v1/fields";
                                            const stringToSign = requestMethod + requestResource + currentUnixTimeInSeconds;
                                            const value = CryptoJS.HmacSHA256(stringToSign, secretApiKey).toString(CryptoJS.enc.Hex);

                                            return { value, currentUnixTimeInSeconds };
                                        }

                                        retrieveLogFields();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");
                                        
                                        var response = await client.GetAsync("https://api.flightreader.com/v1/fields");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }
                                }
                            

                                using System.IO.Compression;
                                using System.Security.Cryptography;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API keys
                                        const string publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Create a request signature used by the Flight Reader API to verify the request was
                                        // initiated by you. This signature will expire 5 minutes after it's created.
                                        var currentUnixTimeInSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                                        var requestMethod = "GET";
                                        var requestResource = "/v1/fields";
                                        var stringToSign = requestMethod + requestResource + currentUnixTimeInSeconds;
                                        var signature = CreateSignature(stringToSign, secretApiKey);
                                        
                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {publicApiKey}");
                                        client.DefaultRequestHeaders.Add("Api-Signature", signature);
                                        client.DefaultRequestHeaders.Add("Api-Timestamp", currentUnixTimeInSeconds.ToString());
                                        
                                        var response = await client.GetAsync("https://api.flightreader.com/v1/fields");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }

                                    private static string CreateSignature(string value, string key)
                                    {
                                        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
                                        var dataBytes = Encoding.UTF8.GetBytes(value);
                                        var hashBytes = hmac.ComputeHash(dataBytes);

                                        return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
                                    }
                                }
                            

Response

                                {
                                    "statusCode": 200,
                                    "message": "GET Request successful.",
                                    "result": [
                                        {
                                            "name": "APP_Message",
                                            "displayName": "APP.message",
                                            "description": "An informational message generated by the application being used to control the aircraft."
                                        },
                                        {
                                            "name": "APP_Tip",
                                            "displayName": "APP.tip",
                                            "description": "An informational message generated by the application being used to control the aircraft."
                                        },
                                        {...},
                                        {...}
                                    ]
                                }
                            




Delete API keys
Deletes a set of secret and public API keys from your account.

DELETE /v1/keys/{key}

                                <html>

                                <body>
                                    <div id="output">Deleting API key...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Set this to the secret key to delete. The associated public key will also be deleted.
                                        const secretApiKeyToDelete = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        async function deleteApiKey() {
                                            try {
                                                const response = await fetch(`https://api.flightreader.com/v1/keys/${secretApiKeyToDelete}`, {
                                                    method: "DELETE",
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        deleteApiKey();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Set this to the secret key to delete. The associated public key will also be deleted.
                                        const string secretApiKeyToDelete = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");

                                        var response = await client.DeleteAsync($"https://api.flightreader.com/v1/keys/{secretApiKeyToDelete}");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }
                                }
                            

Response

                                {
                                    "statusCode": 200,
                                    "message": "DELETE Request successful."
                                }
                            




Retrieve API keys
Retrieves all active API keys from your account.

GET /v1/keys

                                <html>

                                <body>
                                    <div id="output">Retrieving API keys...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        async function retrieveApiKeys() {
                                            try {
                                                const response = await fetch("https://api.flightreader.com/v1/keys", {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        retrieveApiKeys();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");

                                        var response = await client.GetAsync("https://api.flightreader.com/v1/keys");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }
                                }
                            

Response

                                {
                                    "statusCode": 200,
                                    "message": "GET Request successful.",
                                    "result": [
                                        {
                                            "publicKey": "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                                            "secretKey": "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                                            "createdUtc": "2023-08-21T11:37:38Z"
                                        },
                                        {...},
                                        {...}
                                    ]
                                }
                            




Create API key
Creates a new set of secret and public API keys in your account.

GET /v1/keys

                                <html>

                                <body>
                                    <div id="output">Creating API key...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        async function createApiKey() {
                                            try {
                                                const response = await fetch("https://api.flightreader.com/v1/keys", {
                                                    method: "POST",
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        createApiKey();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");

                                        var response = await client.PostAsync("https://api.flightreader.com/v1/keys", null);

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }
                                }
                            

Response

                                {
                                    "statusCode": 201,
                                    "message": "POST Request successful.",
                                    "result": {
                                        "publicKey": "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                                        "secretKey": "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                                    }
                                }
                            




Retrieve flight log field
Retrieves a single flight log field by name.

GET /v1/fields/{field-name}

                                <html>

                                <body>
                                    <div id="output">Retrieving log field...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Call the "/api/v1/fields" endpoint to see a complete list of log fields that can be set here
                                        const fieldName = "OSD_IsGpsUsed";

                                        async function retrieveLogField() {
                                            try {
                                                const response = await fetch(`https://api.flightreader.com/v1/fields/${fieldName}`, {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        retrieveLogField();
                                    </script>
                                </body>

                                </html>
                            

                                <html>

                                <body>
                                    <!-- https://github.com/brix/crypto-js -->
                                    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

                                    <div id="output">Retrieving log field...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Call the "/api/v1/fields" endpoint to see a complete list of log fields that can be set here
                                        const fieldName = "OSD_IsGpsUsed";

                                        async function retrieveLogField() {
                                            try {
                                                // Create a request signature used by the Flight Reader API to verify the request was
                                                // initiated by you. This signature will expire 5 minutes after it's created.
                                                const signature = createSignature();

                                                const response = await fetch(`https://api.flightreader.com/v1/fields/${fieldName}`, {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${publicApiKey}`,
                                                        "Api-Signature": signature.value,
                                                        "Api-Timestamp": signature.currentUnixTimeInSeconds
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        function createSignature() {
                                            const currentUnixTimeInSeconds = Math.floor(Date.now() / 1000);
                                            const requestMethod = "GET";
                                            const requestResource = "/v1/fields/OSD_IsGpsUsed";
                                            const stringToSign = requestMethod + requestResource + currentUnixTimeInSeconds;
                                            const value = CryptoJS.HmacSHA256(stringToSign, secretApiKey).toString(CryptoJS.enc.Hex);

                                            return { value, currentUnixTimeInSeconds };
                                        }

                                        retrieveLogField();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");

                                        const string fieldName = "OSD_IsGpsUsed";
                                        var response = await client.GetAsync($"https://api.flightreader.com/v1/fields/{fieldName}");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }
                                }
                            

                                using System.IO.Compression;
                                using System.Security.Cryptography;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API keys
                                        const string publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Create a request signature used by the Flight Reader API to verify the request was
                                        // initiated by you. This signature will expire 5 minutes after it's created.
                                        var currentUnixTimeInSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                                        var requestMethod = "GET";
                                        var requestResource = "/v1/fields/OSD_IsGpsUsed";
                                        var stringToSign = requestMethod + requestResource + currentUnixTimeInSeconds;
                                        var signature = CreateSignature(stringToSign, secretApiKey);

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {publicApiKey}");
                                        client.DefaultRequestHeaders.Add("Api-Signature", signature);
                                        client.DefaultRequestHeaders.Add("Api-Timestamp", currentUnixTimeInSeconds.ToString());

                                        const string fieldName = "OSD_IsGpsUsed";
                                        var response = client.GetAsync($"https://api.flightreader.com/v1/fields/{fieldName}").Result;

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }

                                    private static string CreateSignature(string value, string key)
                                    {
                                        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
                                        var dataBytes = Encoding.UTF8.GetBytes(value);
                                        var hashBytes = hmac.ComputeHash(dataBytes);

                                        return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
                                    }
                                }
                            

Response

                                {
                                    "statusCode": 200,
                                    "message": "GET Request successful.",
                                    "result": {
                                        "name": "OSD_IsGpsUsed",
                                        "displayName": "OSD.isGPSUsed",
                                        "description": "When true, the aircraft is able to use the GPS satellite data for positioning purposes."
                                    }
                                }
                            




Process a flight log file
Uploads a TXT flight log, processes it, and returns the flight log data in CSV format. For best performance, specify only the flight log fields you need included in the returned CSV file.

Note: The submitted flight log file is only stored in memory while the flight log is being processed. The contents of the processed flight log are never logged or stored anywhere on the Flight Reader API servers.

POST /v1/logs

                                <html>

                                <body>
                                    <input type="file" id="fileInput">
                                    <br><br>
                                    <div id="output"></div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Call the "/api/v1/fields" endpoint to see a complete list of log fields that can be set here
                                        const fields = ["OSD_FlyTimeMilliseconds", "OSD_Latitude", "OSD_Longitude"];

                                        async function processFlightLog() {
                                            try {
                                                const formData = new FormData();
                                                formData.append("file", fileInput.files[0]);

                                                // Remove this forEach loop if you'd like to retrieve all available fields
                                                fields.forEach((value, index) => {
                                                    formData.append("fields", value);
                                                });

                                                const response = await fetch("https://api.flightreader.com/v1/logs", {
                                                    method: "POST",
                                                    body: formData,
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const blob = await response.blob();
                                                    const url = window.URL.createObjectURL(blob);
                                                    const link = document.createElement("a");

                                                    link.href = url;
                                                    link.setAttribute("download", "DJIFlightRecord.csv");
                                                    link.setAttribute("target", "_blank");
                                                    document.body.appendChild(link);
                                                    link.click();

                                                    output.textContent = "CSV file successfully downloaded";
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                            finally {
                                                fileInput.value = null;
                                            }
                                        }

                                        fileInput.addEventListener("change", () => {
                                            output.textContent = "Processing flight log file...";

                                            processFlightLog();
                                        });
                                    </script>
                                </body>

                                </html>  
                            

                                <html>

                                <body>
                                    <!-- https://github.com/brix/crypto-js -->
                                    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

                                    <input type="file" id="fileInput">
                                    <br><br>
                                    <div id="output"></div>

                                    <script>
                                        // Replace with your Flight Reader API keys
                                        const publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Call the "/api/v1/fields" endpoint to see a complete list of log fields that can be set here
                                        const fields = ["OSD_FlyTimeMilliseconds", "OSD_Latitude", "OSD_Longitude"];
                                        
                                        async function processFlightLog() {
                                            try {
                                                const formData = new FormData();
                                                formData.append("file", fileInput.files[0]);

                                                // Remove this forEach loop if you'd like to retrieve all available fields
                                                fields.forEach((value, index) => {
                                                    formData.append("fields", value);
                                                });

                                                // Create a request signature used by the Flight Reader API to verify the request was
                                                // initiated by you. This signature will expire 5 minutes after it's created.
                                                const signature = createSignature(formData);

                                                const response = await fetch("https://api.flightreader.com/v1/logs", {
                                                    method: "POST",
                                                    body: formData,
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${publicApiKey}`,
                                                        "Api-Signature": signature.value,
                                                        "Api-Timestamp": signature.currentUnixTimeInSeconds
                                                    }
                                                });

                                                if (response.ok) {
                                                    const blob = await response.blob();
                                                    const url = window.URL.createObjectURL(blob);
                                                    const link = document.createElement("a");
                                                    link.href = url;
                                                    link.setAttribute("download", "DJIFlightRecord.csv");
                                                    link.setAttribute("target", "_blank");
                                                    document.body.appendChild(link);
                                                    link.click();

                                                    output.textContent = "CSV file successfully downloaded";
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                            finally {
                                                fileInput.value = null;
                                            }
                                        }

                                        function formDataToString(formData) {
                                            const excludedKeys = new Set(["file"]);
                                            const keyValuePairs = {};

                                            for (const [key, value] of formData.entries()) {
                                                if (excludedKeys.has(key)) {
                                                    continue;
                                                }

                                                if (!keyValuePairs[key]) {
                                                    keyValuePairs[key] = [value];
                                                } else {
                                                    keyValuePairs[key].push(value);
                                                }
                                            }

                                            return Object.entries(keyValuePairs)
                                                .map(([key, values]) => `${key}=${values.join(",")}`)
                                                .join("&");
                                        }

                                        function createSignature(formData) {
                                            const currentUnixTimeInSeconds = Math.floor(Date.now() / 1000);
                                            const requestMethod = "POST";
                                            const requestResource = "/v1/logs";
                                            const formDataString = formDataToString(formData);
                                            const stringToSign = requestMethod + requestResource + formDataString + currentUnixTimeInSeconds;
                                            const value = CryptoJS.HmacSHA256(stringToSign, secretApiKey).toString(CryptoJS.enc.Hex);

                                            return { value, currentUnixTimeInSeconds };
                                        }

                                        fileInput.addEventListener("change", () => {
                                            output.textContent = "Processing flight log file...";

                                            processFlightLog();
                                        });
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Net.Http.Headers;
                                using System.Text;

                                internal class Program
                                {
                                    static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        const string logFilePath = "C:\\DJIFlightRecord_2020-12-08_[13-39-22].txt";

                                        var fields = new List<string>
                                        {
                                            "OSD_FlyTimeMilliseconds",
                                            "OSD_Latitude",
                                            "OSD_Longitude"
                                        };

                                        var formContent = new MultipartFormDataContent();

                                        // Add file to form
                                        var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(logFilePath));

                                        fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
                                        {
                                            Name = "file",
                                            FileName = Path.GetFileName(logFilePath)
                                        };

                                        fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                                        formContent.Add(fileContent);

                                        // Add fields to form (remove this foreach loop if you'd like to retrieve all available fields)
                                        foreach (var field in fields)
                                        {
                                            formContent.Add(new StringContent(field), "fields");
                                        }

                                        // Process log
                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");

                                        var response = await client.PostAsync("https://api.flightreader.com/v1/logs", formContent);
                                        var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                        if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                        {
                                            using var compressedStream = new MemoryStream(responseBytes);
                                            await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                            using var decompressedStream = new MemoryStream();

                                            await decompressionStream.CopyToAsync(decompressedStream);
                                            responseBytes = decompressedStream.ToArray();
                                        }

                                        var responseText = Encoding.UTF8.GetString(responseBytes);
                                        Console.WriteLine(responseText);
                                    }
                                }
                            

                                using System.IO.Compression;
                                using System.Net.Http.Headers;
                                using System.Security.Cryptography;
                                using System.Text;

                                internal class Program
                                {
                                    private static async Task Main()
                                    {
                                        // Replace with your Flight Reader API keys
                                        const string publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        const string logFilePath = "C:\\DJIFlightRecord_2020-12-08_[13-39-22].txt";

                                        var fields = new List<string>
                                        {
                                            "OSD_FlyTimeMilliseconds",
                                            "OSD_Latitude",
                                            "OSD_Longitude"
                                        };

                                        var formContent = new MultipartFormDataContent();

                                        // Add file to form
                                        var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(logFilePath));

                                        fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
                                        {
                                            Name = "file",
                                            FileName = Path.GetFileName(logFilePath)
                                        };

                                        fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                                        formContent.Add(fileContent);

                                        // Add fields to form (remove this foreach loop if you'd like to retrieve all available fields)
                                        foreach (var field in fields)
                                        {
                                            formContent.Add(new StringContent(field), "fields");
                                        }
                                        
                                        // Create a request signature used by the Flight Reader API to verify the request was
                                        // initiated by you. This signature will expire 5 minutes after it's created.
                                        var currentUnixTimeInSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                                        var requestMethod = "POST";
                                        var requestResource = "/v1/logs";
                                        var formData = await GetFormDataAsync(formContent);
                                        var stringToSign = $"{requestMethod}{requestResource}{formData}{currentUnixTimeInSeconds}";
                                        var signature = CreateSignature(stringToSign, secretApiKey);
                                        
                                        // Process log
                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {publicApiKey}");
                                        client.DefaultRequestHeaders.Add("Api-Signature", signature);
                                        client.DefaultRequestHeaders.Add("Api-Timestamp", currentUnixTimeInSeconds.ToString());

                                        var response = await client.PostAsync("https://api.flightreader.com/v1/logs", formContent);
                                        var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                        if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                        {
                                            using var compressedStream = new MemoryStream(responseBytes);
                                            await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                            using var decompressedStream = new MemoryStream();

                                            await decompressionStream.CopyToAsync(decompressedStream);
                                            responseBytes = decompressedStream.ToArray();
                                        }

                                        var responseText = Encoding.UTF8.GetString(responseBytes);
                                        Console.WriteLine(responseText);
                                    }
                                    
                                    private static async Task<string> GetFormDataAsync(MultipartFormDataContent formContent)
                                    {
                                        var formData = "";
                                        var lastFieldName = "";

                                        foreach (var content in formContent)
                                        {
                                            if (content is not StringContent stringContent)
                                            {
                                                continue;
                                            }
                                        
                                            var fieldName = content.Headers.ContentDisposition?.Name?.Trim('"');

                                            if (fieldName != lastFieldName)
                                            {
                                                lastFieldName = fieldName;

                                                if (formData.Length > 0)
                                                {
                                                    formData += "&";
                                                }

                                                formData += $"{fieldName}=";
                                            }
                                            else
                                            {
                                                formData += ",";
                                            }

                                            formData += await stringContent.ReadAsStringAsync();
                                        }

                                        return formData;
                                    }
                                    
                                    private static string CreateSignature(string value, string key)
                                    {
                                        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
                                        var dataBytes = Encoding.UTF8.GetBytes(value);
                                        var hashBytes = hmac.ComputeHash(dataBytes);

                                        return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
                                    }
                                }
                            

Response

                                OSD.flyTime [ms],OSD.latitude,OSD.longitude
                                100,53.62646476704494,16.87070193398017
                                300,53.62646474133018,16.87070199143842
                                500,53.62646469232834,16.870702037681247
                                ...
                            




Process a flight log URL
Processes a TXT flight log located at the specified URL and returns the flight log data in CSV format. The log file can be in TXT format and named like "DJIFlightRecord_2022-05-16_[19-02-56].txt" or in ZIP format and named like "DJIFlightRecord_2022-05-16_[19-02-56].zip". For best performance, specify only the flight log fields you need included in the returned CSV file.

Note: You can pass the flight log download URL (downloadUrl) retrieved from the /v1/logs/{id} endpoint to process a flight log from a user's flight log list in the DJI Cloud.

Note: The submitted flight log file is only stored in memory while the flight log is being processed. The contents of the processed flight log are never logged or stored anywhere on the Flight Reader API servers.

POST /v1/logs

                                <html>

                                <body>
                                    <div id="output">Processing flight log...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Set this URL to the location of the DJI TXT flight log file to download
                                        const flightLogUrl = "https://www.YourWebsite.com/DJIFlightRecord_2020-05-16_[19-02-56].txt";

                                        // Call the "/api/v1/fields" endpoint to see a complete list of log fields that can be set here
                                        const fields = ["OSD_FlyTimeMilliseconds", "OSD_Latitude", "OSD_Longitude"];

                                        async function processFlightLog() {
                                            try {
                                                const output = document.getElementById("output");
                                                const formData = new FormData();
                                                formData.append("url", flightLogUrl);

                                                // Remove this forEach loop if you'd like to retrieve all available fields
                                                fields.forEach((value, index) => {
                                                    formData.append("fields", value);
                                                });

                                                const response = await fetch("https://api.flightreader.com/v1/logs", {
                                                    method: "POST",
                                                    body: formData,
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const blob = await response.blob();
                                                    const url = window.URL.createObjectURL(blob);
                                                    const link = document.createElement("a");

                                                    link.href = url;
                                                    link.setAttribute("download", "DJIFlightRecord.csv");
                                                    link.setAttribute("target", "_blank");
                                                    document.body.appendChild(link);
                                                    link.click();

                                                    output.textContent = "CSV file successfully downloaded";
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        processFlightLog();
                                    </script>
                                </body>

                                </html>
                            

                                <html>

                                <body>
                                    <!-- https://github.com/brix/crypto-js -->
                                    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

                                    <div id="output">Processing flight log...</div>

                                    <script>
                                        // Replace with your Flight Reader API keys
                                        const publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Set this URL to the location of the DJI TXT flight log file to download
                                        const flightLogUrl = "https://www.YourWebsite.com/DJIFlightRecord_2020-05-16_[19-02-56].txt";

                                        // Call the "/api/v1/fields" endpoint to see a complete list of log fields that can be set here
                                        const fields = ["OSD_FlyTimeMilliseconds", "OSD_Latitude", "OSD_Longitude"];
                                        
                                        async function processFlightLog() {
                                            try {
                                                const formData = new FormData();
                                                formData.append("url", flightLogUrl);

                                                // Remove this forEach loop if you'd like to retrieve all available fields
                                                fields.forEach((value, index) => {
                                                    formData.append("fields", value);
                                                });

                                                // Create a request signature used by the Flight Reader API to verify the request was
                                                // initiated by you. This signature will expire 5 minutes after it's created.
                                                const signature = createSignature(formData);

                                                const response = await fetch("https://api.flightreader.com/v1/logs", {
                                                    method: "POST",
                                                    body: formData,
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${publicApiKey}`,
                                                        "Api-Signature": signature.value,
                                                        "Api-Timestamp": signature.currentUnixTimeInSeconds
                                                    }
                                                });

                                                if (response.ok) {
                                                    const blob = await response.blob();
                                                    const url = window.URL.createObjectURL(blob);
                                                    const link = document.createElement("a");

                                                    link.href = url;
                                                    link.setAttribute("download", "DJIFlightRecord.csv");
                                                    link.setAttribute("target", "_blank");
                                                    document.body.appendChild(link);
                                                    link.click();

                                                    output.textContent = "CSV file successfully downloaded";
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        function formDataToString(formData) {
                                            const keyValuePairs = {};

                                            for (const [key, value] of formData.entries()) {
                                                if (!keyValuePairs[key]) {
                                                    keyValuePairs[key] = [value];
                                                } else {
                                                    keyValuePairs[key].push(value);
                                                }
                                            }

                                            return Object.entries(keyValuePairs)
                                                .map(([key, values]) => `${key}=${values.join(",")}`)
                                                .join("&");
                                        }

                                        function createSignature(formData) {
                                            const currentUnixTimeInSeconds = Math.floor(Date.now() / 1000);
                                            const requestMethod = "POST";
                                            const requestResource = "/v1/logs";
                                            const formDataString = formDataToString(formData);
                                            const stringToSign = requestMethod + requestResource + formDataString + currentUnixTimeInSeconds;
                                            const value = CryptoJS.HmacSHA256(stringToSign, secretApiKey).toString(CryptoJS.enc.Hex);

                                            return { value, currentUnixTimeInSeconds };
                                        }

                                        processFlightLog();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    private static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        const string logFileUrl = "https://www.YourWebsite.com/DJIFlightRecord_2020-05-16_[19-02-56].txt";

                                        var fields = new List<string>
                                        {
                                            "OSD_FlyTimeMilliseconds",
                                            "OSD_Latitude",
                                            "OSD_Longitude"
                                        };

                                        var formContent = new MultipartFormDataContent();

                                        // Add url to form
                                        formContent.Add(new StringContent(logFileUrl), "url");

                                        // Add fields to form (remove this foreach loop if you'd like to retrieve all available fields)
                                        foreach (var field in fields)
                                        {
                                            formContent.Add(new StringContent(field), "fields");
                                        }

                                        // Process log
                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");
                                        
                                        var response = await client.PostAsync("https://api.flightreader.com/v1/logs", formContent);
                                        var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                        if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                        {
                                            using var compressedStream = new MemoryStream(responseBytes);
                                            await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                            using var decompressedStream = new MemoryStream();

                                            await decompressionStream.CopyToAsync(decompressedStream);
                                            responseBytes = decompressedStream.ToArray();
                                        }

                                        var responseText = Encoding.UTF8.GetString(responseBytes);
                                        Console.WriteLine(responseText);
                                    }
                                }
                            

                                using System.IO.Compression;
                                using System.Security.Cryptography;
                                using System.Text;

                                internal class Program
                                {
                                    private static async Task Main()
                                    {
                                        // Replace with your Flight Reader API keys
                                        const string publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        const string logFileUrl = "https://www.YourWebsite.com/DJIFlightRecord_2020-05-16_[19-02-56].txt";

                                        var fields = new List<string>
                                        {
                                            "OSD_FlyTimeMilliseconds",
                                            "OSD_Latitude",
                                            "OSD_Longitude"
                                        };

                                        var formContent = new MultipartFormDataContent();

                                        // Add url to form
                                        formContent.Add(new StringContent(logFileUrl), "url");
                                        
                                        // Add fields to form (remove this foreach loop if you'd like to retrieve all available fields)
                                        foreach (var field in fields)
                                        {
                                            formContent.Add(new StringContent(field), "fields");
                                        }

                                        // Create a request signature used by the Flight Reader API to verify the request was
                                        // initiated by you. This signature will expire 5 minutes after it's created.
                                        var currentUnixTimeInSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                                        var requestMethod = "POST";
                                        var requestResource = "/v1/logs";
                                        var formData = await GetFormDataAsync(formContent);
                                        var stringToSign = requestMethod + requestResource + formData + currentUnixTimeInSeconds;
                                        var signature = CreateSignature(stringToSign, secretApiKey);

                                        // Process log
                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {publicApiKey}");
                                        client.DefaultRequestHeaders.Add("Api-Signature", signature);
                                        client.DefaultRequestHeaders.Add("Api-Timestamp", currentUnixTimeInSeconds.ToString());

                                        var response = await client.PostAsync("https://api.flightreader.com/v1/logs", formContent);
                                        var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                        if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                        {
                                            using var compressedStream = new MemoryStream(responseBytes);
                                            await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                            using var decompressedStream = new MemoryStream();

                                            await decompressionStream.CopyToAsync(decompressedStream);
                                            responseBytes = decompressedStream.ToArray();
                                        }

                                        var responseText = Encoding.UTF8.GetString(responseBytes);
                                        Console.WriteLine(responseText);
                                    }

                                    private static async Task<string> GetFormDataAsync(MultipartFormDataContent formContent)
                                    {
                                        var formData = "";
                                        var lastFieldName = "";

                                        foreach (var content in formContent)
                                        {
                                            if (content is not StringContent stringContent)
                                            {
                                                continue;
                                            }

                                            var fieldName = content.Headers.ContentDisposition?.Name?.Trim('"');

                                            if (fieldName != lastFieldName)
                                            {
                                                lastFieldName = fieldName;

                                                if (formData.Length > 0)
                                                {
                                                    formData += "&";
                                                }

                                                formData += $"{fieldName}=";
                                            }
                                            else
                                            {
                                                formData += ",";
                                            }

                                            formData += await stringContent.ReadAsStringAsync();
                                        }

                                        return formData;
                                    }

                                    private static string CreateSignature(string value, string key)
                                    {
                                        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
                                        var dataBytes = Encoding.UTF8.GetBytes(value);
                                        var hashBytes = hmac.ComputeHash(dataBytes);

                                        return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
                                    }
                                }
                            

Response

                                OSD.flyTime [ms],OSD.latitude,OSD.longitude
                                100,53.62646476704494,16.87070193398017
                                300,53.62646474133018,16.87070199143842
                                500,53.62646469232834,16.870702037681247
                                ...
                            




Retrieve flight log list
Retrieves a list of flight logs available in the DJI Cloud for a DJI account id. Use the /v1/accounts/dji endpoint to retrieve the DJI account id.

Note: The flight log download URL (downloadUrl) can be passed to the /v1/logs endpoint to process the flight log without the need to download and upload it to the Flight Reader API.

Optional URL Parameters:
  • Limit
    Sets the maximum number of flight logs to retrieve. The default value is 200.
  • CreatedAfterTimestamp
    Retrieves flight logs uploaded to the DJI Cloud after a specified Unix timestamp in seconds.

GET /v1/logs/{id}

                                <html>

                                <body>
                                    <div id="output">Retrieving flight log list...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Use the "/v1/accounts/dji" endpoint to retrieve this DJI account id
                                        const id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        async function retrieveFlightLogList() {
                                            try {
                                                // The optional "limit" and "createdAfterTimestamp" parameters can be appended to the URL
                                                // like this:
                                                //
                                                // https://api.flightreader.com/v1/logs/${id}?limit=20&createdAfterTimestamp=1680107304788

                                                const response = await fetch(`https://api.flightreader.com/v1/logs/${id}`, {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        retrieveFlightLogList();
                                    </script>
                                </body>

                                </html>
                            

                                <html>

                                <body>
                                    <!-- https://github.com/brix/crypto-js -->
                                    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

                                    <div id="output">Retrieving flight log list...</div>

                                    <script>
                                        // Replace with your Flight Reader API keys
                                        const publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        // Use the "/api/v1/accounts/dji" endpoint to retrieve this DJI account id
                                        const id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        async function retrieveFlightLogList() {
                                            try {
                                                // Create a request signature used by the Flight Reader API to verify the request was
                                                // initiated by you. This signature will expire 5 minutes after it's created.
                                                const signature = createSignature();

                                                // The optional "limit" and "createdAfterTimestamp" parameters can be appended to the URL
                                                // like this:
                                                //
                                                // https://api.flightreader.com/v1/logs/${id}?limit=20&createdAfterTimestamp=1680107304788

                                                const response = await fetch(`https://api.flightreader.com/v1/logs/${id}`, {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`,
                                                        "Api-Signature": signature.value,
                                                        "Api-Timestamp": signature.currentUnixTimeInSeconds
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        function createSignature() {
                                            const currentUnixTimeInSeconds = Math.floor(Date.now() / 1000);
                                            const requestMethod = "GET";
                                            const requestResource = `/v1/logs/${id}`;
                                            const stringToSign = requestMethod + requestResource + currentUnixTimeInSeconds;
                                            const value = CryptoJS.HmacSHA256(stringToSign, secretApiKey).toString(CryptoJS.enc.Hex);

                                            return { value, currentUnixTimeInSeconds };
                                        }

                                        retrieveFlightLogList();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    private static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Use the "/api/v1/accounts/dji" endpoint to retrieve this DJI account id
                                        const string id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // The optional "limit" and "createdAfterTimestamp" parameters can be appended to the URL
                                        // like this:
                                        //
                                        // var response = await client.GetAsync($"https://api.flightreader.com/v1/logs/{id}?limit=20&createdAfterTimestamp=1680107304788");
                                        
                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");

                                        var response = await client.GetAsync($"https://api.flightreader.com/v1/logs/{id}");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }
                                }
                            

                                using System.IO.Compression;
                                using System.Security.Cryptography;
                                using System.Text;

                                internal class Program
                                {
                                    private static async Task Main()
                                    {
                                        // Replace with your Flight Reader API keys
                                        const string publicApiKey = "pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Use the "/api/v1/accounts/dji" endpoint to retrieve this DJI account id
                                        const string id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // The optional "limit" and "createdAfterTimestamp" parameters can be appended to the URL
                                        // like this:
                                        //
                                        // var response = await client.GetAsync($"https://api.flightreader.com/v1/logs/{id}?limit=20&createdAfterTimestamp=1680107304788");

                                        // Create a request signature used by the Flight Reader API to verify the request was
                                        // initiated by you. This signature will expire 5 minutes after it's created.
                                        var currentUnixTimeInSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                                        var requestMethod = "GET";
                                        var requestResource = $"/v1/logs/{id}";
                                        var stringToSign = requestMethod + requestResource + currentUnixTimeInSeconds;
                                        var signature = CreateSignature(stringToSign, secretApiKey);

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {publicApiKey}");
                                        client.DefaultRequestHeaders.Add("Api-Signature", signature);
                                        client.DefaultRequestHeaders.Add("Api-Timestamp", currentUnixTimeInSeconds.ToString());

                                        var response = await client.GetAsync($"https://api.flightreader.com/v1/logs/{id}");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }

                                    private static string CreateSignature(string value, string key)
                                    {
                                        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
                                        var dataBytes = Encoding.UTF8.GetBytes(value);
                                        var hashBytes = hmac.ComputeHash(dataBytes);

                                        return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
                                    }
                                }
                            

Response

                                {
                                    "statusCode": 200,
                                    "message": "GET Request successful.",
                                    "result": [
                                        {
                                            "aircraftName": "Mavic 3",
                                            "aircraftSerialNumber": "125A845TA35AF2AG0220",
                                            "downloadUrl": "https://api.flightreader.com/v1/files/flight-logs/1d8a3d88433bf0a59537c2bc748f68710/DJIFlightRecord_2023-03-29_[12-28-24].txt",
                                            "fileName": "DJIFlightRecord_2023-03-29_[12-28-24].txt",
                                            "maxHeight": 65,
                                            "md5Hash": "436412e045c9ad2db38c18cfc4cb0149",
                                            "timestamp": 1680107304788,
                                            "totalDistance": 1485.5077,
                                            "totalTime": 165400
                                        },
                                        {...},
                                        {...}
                                    ]
                                }
                            




Retrieve DJI account id
Retrieves a unique id for a DJI account. This id is needed in order to retrieve the flight log list for a DJI account.

Once this id has been retrieved, you can continue to use it until the password is reset on the associated DJI account. At that point, the Flight Reader API will return a 401 Unauthorized response status code indicating that the id is no longer valid.

Note: The submitted DJI account credentials are only stored in memory long enough to retrieve the unique id. Those details are never logged or stored anywhere on the Flight Reader API servers.

POST /v1/accounts/dji

Response

                                {
                                    "statusCode": 200,
                                    "message": "POST Request successful.",
                                    "result": {
                                        "id": "a014f2df954b87acd647918c73a9cffc"
                                    }
                                }
                            




Retrieve API usage
Retrieve a list of API requests made by your API account.

Optional URL Parameters:
  • Limit
    Sets the maximum number of days to retrieve. The default value is 30.

GET /v1/usage

                                <html>

                                <body>
                                    <div id="output">Retrieving API usage...</div>

                                    <script>
                                        // Replace with your Flight Reader API secret key
                                        const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        // Note: You should never expose your API secret key like this in a production environment.
                                        //       Anyone who has access to it will be able to make API requests on your behalf.

                                        async function retrieveApiUsage() {
                                            try {
                                                // The optional "limit" parameter can be appended to the URL like this:
                                                //
                                                // https://api.flightreader.com/v1/usage?limit=7

                                                const response = await fetch(`https://api.flightreader.com/v1/usage`, {
                                                    headers: {
                                                        "Accept-Encoding": "gzip",
                                                        "Authorization": `Bearer ${secretApiKey}`
                                                    }
                                                });

                                                if (response.ok) {
                                                    const data = await response.json();
                                                    output.textContent = JSON.stringify(data.result);
                                                } else {
                                                    output.textContent = `${response.status} ${response.statusText}`;
                                                }
                                            } catch (error) {
                                                output.textContent = error;
                                            }
                                        }

                                        retrieveApiUsage();
                                    </script>
                                </body>

                                </html>
                            

                                using System.IO.Compression;
                                using System.Text;

                                internal class Program
                                {
                                    private static async Task Main()
                                    {
                                        // Replace with your Flight Reader API secret key
                                        const string secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

                                        using HttpClient client = new();
                                        client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
                                        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretApiKey}");

                                        // The optional "limit" parameter can be appended to the URL like this:
                                        //
                                        // https://api.flightreader.com/v1/usage?limit=7

                                        var response = await client.GetAsync("https://api.flightreader.com/v1/usage");

                                        if (response.IsSuccessStatusCode)
                                        {
                                            var responseBytes = await response.Content.ReadAsByteArrayAsync();

                                            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
                                            {
                                                using var compressedStream = new MemoryStream(responseBytes);
                                                await using var decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress);
                                                using var decompressedStream = new MemoryStream();

                                                await decompressionStream.CopyToAsync(decompressedStream);
                                                responseBytes = decompressedStream.ToArray();
                                            }

                                            var responseText = Encoding.UTF8.GetString(responseBytes);
                                            Console.WriteLine(responseText);
                                        }
                                        else
                                        {
                                            Console.WriteLine($"Error: {response.StatusCode}");
                                        }
                                    }
                                }
                            

Response

                                {
                                    "statusCode": 200,
                                    "message": "GET Request successful.",
                                    "result": {
                                        "totalRequests": 9,
                                        "requestsByDate": [
                                            {
                                                "date": "2023-08-31",
                                                "totalRequests": 8,
                                                "requests": [
                                                    {
                                                        "endpoint": "/accounts/dji",
                                                        "count": 2
                                                    },
                                                    {
                                                        "endpoint": "/logs/{id}",
                                                        "count": 6
                                                    }
                                                ]
                                            },
                                            {...},
                                            {...}
                                        ]
                                    }
                                }