Upload media (pre-upload for tweets)
curl --request POST \
--url https://api.aisa.one/apis/v1/twitter/upload_media \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form media_files='@example-file' \
--form 'aisa_api_key=<string>'import requests
url = "https://api.aisa.one/apis/v1/twitter/upload_media"
files = { "media_files": ("example-file", open("example-file", "rb")) }
payload = { "aisa_api_key": "<string>" }
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('media_files', '<string>');
form.append('aisa_api_key', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.aisa.one/apis/v1/twitter/upload_media', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.aisa.one/apis/v1/twitter/upload_media",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.aisa.one/apis/v1/twitter/upload_media"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.aisa.one/apis/v1/twitter/upload_media")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.aisa.one/apis/v1/twitter/upload_media")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"data": {
"media_id": "2099415764780605440"
}
}Post & Actions
Upload Media
Upload an image, GIF, or video and get a media_id to attach to a tweet. Multipart/form-data only.
POST
https://api.aisa.one/apis/v1
/
twitter
/
upload_media
Upload media (pre-upload for tweets)
curl --request POST \
--url https://api.aisa.one/apis/v1/twitter/upload_media \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form media_files='@example-file' \
--form 'aisa_api_key=<string>'import requests
url = "https://api.aisa.one/apis/v1/twitter/upload_media"
files = { "media_files": ("example-file", open("example-file", "rb")) }
payload = { "aisa_api_key": "<string>" }
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('media_files', '<string>');
form.append('aisa_api_key', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.aisa.one/apis/v1/twitter/upload_media', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.aisa.one/apis/v1/twitter/upload_media",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.aisa.one/apis/v1/twitter/upload_media"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.aisa.one/apis/v1/twitter/upload_media")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.aisa.one/apis/v1/twitter/upload_media")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"media_files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aisa_api_key\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"data": {
"media_id": "2099415764780605440"
}
}Upload a single image, GIF, or video and receive a
Then attach it:
media_id you can attach to a tweet via post_twitter, routed through the AIsa gateway at https://api.aisa.one/apis/v1/twitter/upload_media.
This endpoint accepts
multipart/form-data only — send the file as a form part. Sending a JSON body returns 400 "upload_media requires multipart/form-data with a single media file field".Prerequisites
- An AIsa API key (Bearer token for every request).
- A one-time OAuth authorization for the source user. Link your X account via
POST /apis/v1/twitter/auth_twitter. - The X session must hold
media.write,tweet.read,users.read.
Two-step media flow
- Upload —
POST /apis/v1/twitter/upload_mediawith the file → returnsmedia_id. - Publish —
POST /apis/v1/twitter/post_twitterwith{ "media": { "media_ids": ["<media_id>"] } }.
post_twitter also accepts inline file parts via media_files in a single multipart request, letting you skip the pre-upload step. Use upload_media when you want to reuse one asset across several tweets, or decouple a large upload from the publish call.Example
curl -X POST "https://api.aisa.one/apis/v1/twitter/upload_media" \
-H "Authorization: Bearer $AISA_API_KEY" \
-F "media_files=@./cat.png;type=image/png"
Response
{ "code": 200, "msg": "Media uploaded successfully", "data": { "media_id": "2099415764780605440" } }
curl -X POST "https://api.aisa.one/apis/v1/twitter/post_twitter" \
-H "Authorization: Bearer $AISA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Look at this cat","media":{"media_ids":["2099415764780605440"]}}'
Notes
- The file field may be named
media_files,media, orfile. - Images up to 8 MB use a single-shot upload; larger files and video are chunked automatically.
- Unattached media expires after ~24h.
- Media upload is a prerequisite step and is not separately metered — you are billed when you publish the tweet via
post_twitter.
Related
Post a Tweet
Attach the media_id via
media.media_ids.Link an X Account
Start the OAuth flow this endpoint requires.
Like a Tweet
Another write endpoint using the same OAuth session.
Authorizations
Your AIsa API key. The authenticated source user (the account doing the follow) is determined by the OAuth session attached to your key.
Body
multipart/form-data
The media file to upload (image/*, image/gif, or video/*). The field may also be named media or file. Images up to 8 MB use a single-shot upload; larger files and video use chunked upload automatically.
Optional. Normally unnecessary — the gateway resolves your account from the Authorization: Bearer header.
Response
Upload succeeded; returns the media_id to reference in post_twitter.
Show child attributes
Show child attributes