title: Firebase v1 HTTP api does not support nested JSON objects
body: <p><strong>CURRENT SITUATION</strong></p>
  
  <p>We send a POST request <a href="https://firebase.google.com/docs/cloud-messaging/http-server-ref" rel="nofollow noreferrer">Firebase legacy URL</a> <code>https://fcm.googleapis.com/fcm/send</code> to deliver notification JSON payload to our Android application. Our notification payload is a nested JSON object within a standard data. Our sample payload from Postman is given below</p>
  
  <pre><code>{
   "registration_ids": [
     "${registration_id}"],
     "priority":"HIGH", 
   "data": {
     "notification": {
       "title": "Notification Data Title From Postman",
       "body": "Notification Data Body From Postman",
       "imageurl": "https://d2x51gyc4ptf2q.cloudfront.net/content/uploads/2015/10/GettyImages-51205958-700x367.jpg"
     },
     "fcm_options": {
             "analytics_label": "postman"
       }
   }
  }
  </code></pre>
  
  <p>The request headers are as follows:</p>
  
  <pre><code>Content-Type: application/json; charset=utf-8`
  Authorization: key={{server_key}}
  </code></pre>
  
  <p>In this example, the nested JSON object within the data object as shown below is used to successfully construct the notification.</p>
  
  <pre><code>"data": {
         "notification": {
           "title": "Notification Data Title From Postman",
           "body": "Notification Data Body From Postman",
           "imageurl": "https://d2x51gyc4ptf2q.cloudfront.net/content/uploads/2015/10/GettyImages-51205958-700x367.jpg"
         }
  }
  </code></pre>
  
  <p>The server key is obtained from the Firebase console's project settings. This payload is successfully delivered to an Android app on an appropriate device to create a notification.</p>
  
  <p><strong>PROBLEM</strong></p>
  
  <p>We want to migrate to <a href="https://firebase.google.com/docs/cloud-messaging/migrate-v1" rel="nofollow noreferrer">Firebase v1 HTTP request APIs</a>. I am attempting to use <a href="https://firebase.google.com/docs/cloud-messaging/migrate-v1#use_credentials_to_mint_access_tokens" rel="nofollow noreferrer">OAuth2 Tokens</a> to authenticate and deliver notifications to the Android device. The payload that I want to send through V1 api is given below</p>
  
  <pre><code>{
    "message": {
      "token": "${token}",
      "data": {
        "notification": {
          "title": "Notification Data Title From v1 API",
          "body": "Notification Data Body From v1 API",
          "imageurl": "https://d2x51gyc4ptf2q.cloudfront.net/content/uploads/2015/10/GettyImages-51205958-700x367.jpg",
          "extra_key": "extra_value"
        }
      },
      "android": {
        "priority": "HIGH",
        "fcm_options": {
          "analytics_label": "Test_Command_line"
        }
      }
    }
  }
  </code></pre>
  
  <p>When we make a HTTP POST request to the v1 HTTP API, I get a 400 error with the following error message.</p>
  
  <pre><code>{
    "error": {
      "code": 400,
      "message": "Invalid JSON payload received. Unknown name \"title\" at 'message.data[3].value': Cannot find field.\nInvalid JSON payload received. Unknown name \"body\" at 'message.data[3].value': Cannot find field.\nInvalid JSON payload received. Unknown name \"imageurl\" at 'message.data[3].value': Cannot find field.\nInvalid JSON payload received. Unknown name \"extra_key\" at 'message.data[3].value': Cannot find field.",
      "status": "INVALID_ARGUMENT",
      "details": [
        {
          "@type": "type.googleapis.com/google.rpc.BadRequest",
          "fieldViolations": [
            {
              "field": "message.data[3].value",
              "description": "Invalid JSON payload received. Unknown name \"title\" at 'message.data[3].value': Cannot find field."
            },
            {
              "field": "message.data[3].value",
              "description": "Invalid JSON payload received. Unknown name \"body\" at 'message.data[3].value': Cannot find field."
            },
            {
              "field": "message.data[3].value",
              "description": "Invalid JSON payload received. Unknown name \"imageurl\" at 'message.data[3].value': Cannot find field."
            },
            {
              "field": "message.data[3].value",
              "description": "Invalid JSON payload received. Unknown name \"extra_key\" at 'message.data[3].value': Cannot find field."
            }
          ]
        }
      ]
    }
  }
  </code></pre>
  
  <p>But when the data payload is not nested as given below</p>
  
  <pre><code>"data": {
      "title": "Title that is not nested",
      "body": "Body that is not nested",
      "imageurl": "https://timedotcom.files.wordpress.com/2016/08/margot-robbie-beer-shower.jpg",
  }
  </code></pre>
  
  <p>then I get a 200 OK response. The response body is given below</p>
  
  <pre><code>{
    "name": "projects/&lt;project_id&gt;/messages/&lt;message_id&gt;"
  }
  </code></pre>
  
  <p><strong>DESIRED BEHAVIOUR</strong></p>
  
  <p>I want to be able to deliver nested <code>data</code> payloads using Firebase v1 HTTP API to our Android app so that the notifications can be rendered. How can I achieve that given that I am getting errors when I send nested payloads? This is the program that I have been using to make HTTP requests. The program uses Google-API clients, FreeMarker, Firebase-Admin, and OKHttp.</p>
  
  <pre><code>public class FCMMessaging {
  
      public static void main(String[] args) throws IOException, FirebaseMessagingException {
  
          // File was downloaded from Firebase console URL: https://console.firebase.google.com/project/&lt;project-id&gt;/settings/serviceaccounts/adminsdk
          try(InputStream is =
                  FCMMessaging.class.getClassLoader().getResourceAsStream("firebase-admin-service-account.json");) {
  
              GoogleCredential googleCredential = GoogleCredential
                      .fromStream(is)
                      .createScoped(Collections.singletonList("https://www.googleapis.com/auth/firebase.messaging"));
              googleCredential.refreshToken();
              String bearerToken = googleCredential.getAccessToken();
  
              Configuration cfg = new Configuration();
  
              // Where do we load the notification payload templates from:
              cfg.setClassForTemplateLoading(FCMMessaging.class, "");
  
              // Some other recommended settings:
              cfg.setDefaultEncoding("UTF-8");
              cfg.setLocale(Locale.US);
              cfg.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
              Map&lt;String, Object&gt; templateMap = new HashMap&lt;&gt;();
              templateMap.put("token",
                      "my-token-id");
  
              Template template = cfg.getTemplate("notification_payload.json");
              StringWriter stringWriter = new StringWriter();
              template.process(templateMap, stringWriter);
              RequestBody requestBody = RequestBody.create(stringWriter.toString(), MediaType.get("application/json; charset=utf-8"));
              Request request = new Request.Builder().url("https://fcm.googleapis.com/v1/projects/&lt;project-id&gt;/messages:send")
                      .addHeader("Authorization", "Bearer " + bearerToken).post(requestBody).build();
  
              OkHttpClient client = new OkHttpClient();
              try (Response response = client.newCall(request).execute()) {
                  System.out.println(response.body().string());
              }
          } catch (TemplateException te) {
              te.printStackTrace();
          }
      }
  }
  </code></pre>