title: How to POST an image to imgbb.com on ESP32 CAM? I get "Empty upload source."
body: <p>I'm a DIYer and I'm trying to upload a picture from ESP32-CAM to imgbb.com using POST. <a href="https://randomnerdtutorials.com/esp32-cam-shield-pcb-telegram/" rel="nofollow noreferrer">This project</a> from RandomNerdTutorials gave me a better notion about POST request on C++.</p>
  <p>I took their code and modified it to upload to <a href="https://api.imgbb.com" rel="nofollow noreferrer">https://api.imgbb.com</a>.</p>
  <pre class="lang-cpp prettyprint-override"><code>/*
    Rui Santos
    Complete project details at https://RandomNerdTutorials.com/esp32-cam-shield-pcb-telegram/
    
    Project created using Brian Lough's Universal Telegram Bot Library: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
  
    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.
  */
  // Partial code modified to upload to imgbb.com
  String uploadPhoto(char *apikey){
    String getAll = &quot;&quot;;
    String getBody = &quot;&quot;;
  
    camera_fb_t * fb = NULL;
    fb = esp_camera_fb_get();  
    if(!fb) {
      Serial.println(&quot;Camera capture failed&quot;);
      delay(1000);
      ESP.restart();
      return &quot;Camera capture failed&quot;;
    }
    
    Serial.println(&quot;Connect to api.imgbb.com&quot;);
  
    if (clientTCP.connect(&quot;api.imgbb.com&quot;, 443)) {
      Serial.println(&quot;Connection successful&quot;);
      
      String head = &quot;--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\&quot;photo.jpg\&quot;; filename=\&quot;photo.jpg\&quot;\r\nContent-Type: image/jpeg\r\n\r\n&quot;;
      // String head = &quot;--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\&quot;photo.jpg\&quot;; filename=\&quot;photo.jpg\&quot;\r\n\r\n&quot;;
      String tail = &quot;\r\n--RandomNerdTutorials--\r\n&quot;;
  
      uint16_t imageLen = fb-&gt;len;
      uint16_t extraLen = head.length() + tail.length();
      uint16_t totalLen = imageLen + extraLen;
  
      Serial.printf(&quot;imageLen:%d - extraLen: %d - totalLen: %d\n&quot;, imageLen, extraLen, totalLen);
    
      clientTCP.println(&quot;POST /1/upload?expiration=600&amp;key=&quot;+String(apikey)+&quot; HTTP/1.1&quot;);
      clientTCP.println(&quot;Host: api.imgbb.com&quot;);
      clientTCP.println(&quot;Content-Length: &quot; + String(totalLen));
      clientTCP.println(&quot;Content-Type: multipart/form-data; boundary=RandomNerdTutorials&quot;);
      clientTCP.println();
      clientTCP.print(head);
    
      uint8_t *fbBuf = fb-&gt;buf;
      size_t fbLen = fb-&gt;len;
      Serial.printf(&quot;fbLen: %d\n&quot;, fbLen);
      int count = 0;
      for (size_t n=0;n&lt;fbLen;n=n+1024) {
        count++;
        Serial.printf(&quot;Sending part %d\n&quot;, count);
        if (n+1024&lt;fbLen) {
          clientTCP.write(fbBuf, 1024);
          fbBuf += 1024;
        }
        else if (fbLen%1024&gt;0) {
          size_t remainder = fbLen%1024;
          clientTCP.write(fbBuf, remainder);
        }
      }
      
      clientTCP.print(tail);
      
      esp_camera_fb_return(fb);
      
      unsigned long now = millis();
      boolean state = false;
      
      while (millis() - now &lt; 10000){ // timeout 10 seconds
        Serial.print(&quot;.&quot;);
        delay(100);      
        while (clientTCP.available()){
            char c = clientTCP.read();
            if (c == '\n'){
              if (getAll.length()==0) state=true; 
              getAll = &quot;&quot;;
            } 
            else if (c != '\r'){
              getAll += String(c);
            }
            if (state==true){
              getBody += String(c);
            }
         }
         if (getBody.length()&gt;0) break;
      }
      clientTCP.stop();
      Serial.println(getBody);
    }
    else {
      getBody=&quot;Connected to api.imgbb.com failed.&quot;;
      Serial.println(&quot;Connected to api.imgbb.com failed.&quot;);
    }
    return getBody;
  }
  </code></pre>
  <p>I get this on Serial Monitor</p>
  <pre class="lang-sh prettyprint-override"><code>Connection successful
  imageLen:7522 - extraLen: 150 - totalLen: 7672
  fbLen: 7522
  Sending part 1
  Sending part 2
  Sending part 3
  Sending part 4
  Sending part 5
  Sending part 6
  Sending part 7
  Sending part 8
  ..
  7a
  {&quot;status_code&quot;:400,&quot;error&quot;:{&quot;message&quot;:&quot;Empty upload source.&quot;,&quot;code&quot;:130,&quot;context&quot;:&quot;Exception&quot;},&quot;status_txt&quot;:&quot;Bad Request&quot;}
  </code></pre>
  <p>In case you are asking for the cURL example output on their API site, the output using <code>-v</code> option prints:
  With command</p>
  <pre class="lang-sh prettyprint-override"><code>curl --location --request POST &quot;https://api.imgbb.com/1/upload?expiration=600&amp;key=YOUR_CLIENT_API_KEY&quot; --form image=@&quot;example.jpg&quot; -v
  </code></pre>
  <pre class="lang-sh prettyprint-override"><code>Note: Unnecessary use of -X or --request, POST is already inferred.
  *   Trying 51.81.57.189...
  * TCP_NODELAY set
  * Connected to api.imgbb.com (51.81.57.189) port 443 (#0)
  * schannel: SSL/TLS connection with api.imgbb.com port 443 (step 1/3)
  * schannel: checking server certificate revocation
  * schannel: sending initial handshake data: sending 178 bytes...
  * schannel: sent initial handshake data: sent 178 bytes
  * schannel: SSL/TLS connection with api.imgbb.com port 443 (step 2/3)
  * schannel: failed to receive handshake, need more data
  * schannel: SSL/TLS connection with api.imgbb.com port 443 (step 2/3)
  * schannel: encrypted data got 3525
  * schannel: encrypted data buffer: offset 3525 length 4096
  * schannel: sending next handshake data: sending 93 bytes...
  * schannel: SSL/TLS connection with api.imgbb.com port 443 (step 2/3)
  * schannel: encrypted data got 51
  * schannel: encrypted data buffer: offset 51 length 4096
  * schannel: SSL/TLS handshake complete
  * schannel: SSL/TLS connection with api.imgbb.com port 443 (step 3/3)
  * schannel: stored credential handle in session cache
  &gt; POST /1/upload?expiration=600&amp;key=1be33137765dd807cb05b2ff94885779 HTTP/1.1
  &gt; Host: api.imgbb.com
  &gt; User-Agent: curl/7.55.1
  &gt; Accept: */*
  &gt; Content-Length: 18608
  &gt; Expect: 100-continue
  &gt; Content-Type: multipart/form-data; boundary=------------------------c67a7796e0413135
  &gt;
  * schannel: client wants to read 102400 bytes
  * schannel: encdata_buffer resized 103424
  * schannel: encrypted data buffer: offset 0 length 103424
  * schannel: encrypted data got 54
  * schannel: encrypted data buffer: offset 54 length 103424
  * schannel: decrypted data length: 25
  * schannel: decrypted data added: 25
  * schannel: decrypted data cached: offset 25 length 102400
  * schannel: encrypted data buffer: offset 0 length 103424
  * schannel: decrypted data buffer: offset 25 length 102400
  * schannel: schannel_recv cleanup
  * schannel: decrypted data returned 25
  * schannel: decrypted data buffer: offset 0 length 102400
  &lt; HTTP/1.1 100 Continue
  HTTP/1.1 100 Continue
  
  * schannel: client wants to read 102400 bytes
  * schannel: encrypted data buffer: offset 0 length 103424
  * schannel: encrypted data got 1096
  * schannel: encrypted data buffer: offset 1096 length 103424
  * schannel: decrypted data length: 1067
  * schannel: decrypted data added: 1067
  * schannel: decrypted data cached: offset 1067 length 102400
  * schannel: encrypted data buffer: offset 0 length 103424
  * schannel: decrypted data buffer: offset 1067 length 102400
  * schannel: schannel_recv cleanup
  * schannel: decrypted data returned 1067
  * schannel: decrypted data buffer: offset 0 length 102400
  &lt; HTTP/1.1 200 OK
  HTTP/1.1 200 OK
  &lt; Server: nginx
  Server: nginx
  &lt; Date: Mon, 10 Aug 2020 20:08:42 GMT
  Date: Mon, 10 Aug 2020 20:08:42 GMT
  &lt; Content-Type: application/json; charset=UTF-8
  Content-Type: application/json; charset=UTF-8
  &lt; Transfer-Encoding: chunked
  Transfer-Encoding: chunked
  &lt; Connection: keep-alive
  Connection: keep-alive
  &lt; Vary: Accept-Encoding
  Vary: Accept-Encoding
  &lt; Access-Control-Allow-Origin: *
  Access-Control-Allow-Origin: *
  &lt; Access-Control-Allow-Headers: Cache-Control, X-Requested-With, Content-Type
  Access-Control-Allow-Headers: Cache-Control, X-Requested-With, Content-Type
  &lt; Access-Control-Allow-Methods: POST, GET, OPTIONS
  Access-Control-Allow-Methods: POST, GET, OPTIONS
  &lt; Last-Modified: Mon, 10 Aug 2020 20:08:42GMT
  Last-Modified: Mon, 10 Aug 2020 20:08:42GMT
  &lt; Cache-Control: no-cache, must-revalidate
  Cache-Control: no-cache, must-revalidate
  &lt; Pragma: no-cache
  Pragma: no-cache
  
  &lt;
  {&quot;data&quot;:{&quot;id&quot;:&quot;P6Ynw91&quot;,&quot;title&quot;:&quot;pull&quot;,&quot;url_viewer&quot;:&quot;https:\/\/ibb.co\/P6Ynw91&quot;,&quot;url&quot;:&quot;https:\/\/i.ibb.co\/d5cqGLk\/pull.jpg&quot;,&quot;display_url&quot;:&quot;https:\/\/i.ibb.co\/d5cqGLk\/pull.jpg&quot;,&quot;size&quot;:18421,&quot;time&quot;:&quot;1597090122&quot;,&quot;expiration&quot;:&quot;600&quot;,&quot;image&quot;:{&quot;filename&quot;:&quot;pull.jpg&quot;,&quot;name&quot;:&quot;pull&quot;,&quot;mime&quot;:&quot;image\/jpeg&quot;,&quot;extension&quot;:&quot;jpg&quot;,&quot;url&quot;:&quot;https:\/\/i.ibb.co\/d5cqGLk\/pull.jpg&quot;},&quot;thumb&quot;:{&quot;filename&quot;:&quot;pull.jpg&quot;,&quot;name&quot;:&quot;pull&quot;,&quot;mime&quot;:&quot;image\/jpeg&quot;,&quot;extension&quot;:&quot;jpg&quot;,&quot;url&quot;:&quot;https:\/\/i.ibb.co\/P6Ynw91\/pull.jpg&quot;},&quot;delete_url&quot;:&quot;https:\/\/ibb.co\/P6Ynw91\/7912eb21dadf18bcf78119d10ae7b427&quot;},&quot;success&quot;:true,&quot;status&quot;:200}* Connection #0 to host api.imgbb.com left intact
  </code></pre>