FiveM スマホと EdgeVault
使っているスマホの版と公開設定を確認し、メディアの保存先を接続します。各スクリプトとの接続は実機で確認してください。
EdgeVault のアップロード契約
- 送信先
- https://nozawatec.com/api/edgeworks/vault/upload
- 送信形式
- POST / multipart/form-data、ファイル項目名は
file(NPWD のボイスメッセージが送るrecordingも受け付けます) - 認証
X-API-Key。キーはサーバー側に保持します。- 返却 URL
- 成功時の JSON の
data.url(同じ URL を一番上のurlにも返します) - 上限
- 1 ファイル 100 MiB。画像・動画・音声の許可形式は API リファレンスを確認してください。
- 一時 URL
- サーバーから https://nozawatec.com/api/edgeworks/vault/presign に
X-API-Keyとfilename・mime_type・folderを送ると、アップロード用の一時 URL(presigned URL)data.upload_url_with_tokenが返ります(1 時間有効)。スマホや screenshot-basic の画面(https://cfx-nui-…)からの送信も受け付けます。
スマホ側が別のフィールド名や JSON 形式を固定している場合、送信先だけの変更では接続できません。API キーをクライアントへ配らないサーバー側アダプターが必要です。
API リファレンスLB Phone(lb-phone v2.9.0)
有料 · v2.9.0 の配布物で手順を確認 · EdgeVault 側は同じ送りかたで検査済み · FiveM の実機は要確認写真・動画・録音を、lb-phone の「PRESIGNED_URL」の方式で EdgeVault に置きます。EdgeWorks の API キーはサーバーの中だけで使い、プレイヤーの画面には使い切りの送信先だけが渡ります。書き換えるのは 4 つのファイルで、どれも暗号化されていない(編集してよい)場所です。
1. 方式を足す — shared/upload.lua
UploadMethods の表に EdgeVault を足します。Qbox の定義の後ろ(表を閉じる最後の } の手前)に入れてください。鍵(API_KEY)は書きません。送信先の PRESIGNED_URL は、次の手順のサーバーの処理が作った URL に置き換わります。
EdgeVault = { Default = { url = "PRESIGNED_URL", field = "file", error = { path = "success", value = false }, success = { path = "data.url" }, }, },2. 送信先を作る — server/custom/functions/functions.lua
GetPresignedUrl の中の、Qbox の分岐が終わる end)) の後ろ(if を閉じる end の手前)に、EdgeVault の分岐を足します。サーバーから EdgeVault に「これから送るファイルの種類」を伝え、使い切りの送信先を受け取って返します。鍵はここでしか使いません。
elseif uploadMethod == "EdgeVault" then local mime = ({ Image = Config.Image.Mime, Video = "video/webm", Audio = "audio/webm" })[uploadType] if mime == "image/jpg" then mime = "image/jpeg" end -- EdgeVault は正式名の image/jpeg で受ける local ext = ({ ["image/webp"] = "webp", ["image/png"] = "png", ["image/jpeg"] = "jpg", ["video/webm"] = "webm", ["audio/webm"] = "webm" })[mime] or "bin" return Citizen.Await(promise.new(function(p) PerformHttpRequest("https://nozawatec.com/api/edgeworks/vault/presign", function(status, body) local okDecode, res = pcall(json.decode, body or "") local url = okDecode and type(res) == "table" and res.success and res.data and res.data.upload_url_with_token if status ~= 200 or not url then infoprint("error", "EdgeVault: could not create an upload URL (HTTP " .. tostring(status) .. ")") print("Body:", body) p:resolve() return end p:resolve(url) end, "POST", json.encode({ filename = "lb-phone." .. ext, mime_type = mime, folder = "/lb-phone/" .. uploadType, }), { ["Content-Type"] = "application/json", ["X-API-Key"] = apiKey, }) end))3. 鍵を置く — server/apiKeys.lua
API_KEYS の Video・Image・Audio に、EdgeWorks のダッシュボードで発行した API キーを入れます。このファイルはサーバーだけが読み、手順 2 の処理だけが使います。同じ鍵を 3 つに入れてかまいません。
API_KEYS = { Video = "EdgeWorks の API キー", Image = "EdgeWorks の API キー", Audio = "EdgeWorks の API キー", }4. 方式を選び、置き場を許可する — config/config.lua
Config.UploadMethod の 3 つを "EdgeVault" にします。あわせて Config.UploadWhitelistedDomains に nozawatec.com を足します(EdgeVault の公開 URL は https://nozawatec.com/api/edgeworks/files/… です)。足さないと、送れてもスマホの中で写真が受け付けられません。
Config.UploadMethod.Video = "EdgeVault" Config.UploadMethod.Image = "EdgeVault" Config.UploadMethod.Audio = "EdgeVault" Config.UploadWhitelistedDomains = { "fivemanage.com", "fmfile.com", "amazonaws.com", -- lb-presigned (S3) "nozawatec.com", -- EdgeVault }5. 再起動して試す
サーバーを再起動するか、コンソールで restart lb-phone を実行します。写真・動画・ボイスメッセージを 1 つずつ試し、スマホの中で開けることと、EdgeWorks のダッシュボードの Vault の /lb-phone/Image・/lb-phone/Video・/lb-phone/Audio に現れることを確かめてください。失敗したときは、サーバーのコンソールに「EdgeVault: could not create an upload URL」と HTTP の番号が出ます。
気をつけること
- Custom の方式(upload.lua の headers に API_KEY と書く方式)は使わないでください。lb-phone は送信をスマホの画面から行うので、鍵が全プレイヤーの手元に渡ります(以前ここで案内していた手順はこの形だったので、取り下げました)。
- 録音は WebM(audio/webm)で保存されます。EdgeVault の受け取りは、2026-10-25 に録音の WebM を受け付けるようにしました(それより前は断っていました)。
- 大きさ: lb-phone の既定は動画 25 MB・60 秒(Config.Video.MaxSize・Config.Video.MaxDuration)。EdgeVault は 1 ファイル 100 MiB まで、全体の容量はプランごと(無料 10 GiB・Pro 100 GiB・Enterprise 300 GiB)です。
- アップロード用の一時 URL(presigned URL)は 1 回だけ・1 時間有効です。作る口(presign)は 1 つの API キーにつき 1 分 240 回までです。
- スマホの中の写真は EdgeVault の URL を指しているだけです。EdgeVault で消すと、スマホの中でも見られなくなります。
- 写真の形式(Config.Image.Mime)は、既定の image/webp か image/png を使ってください。EdgeVault 側で確かめたのはこの 2 つと WebM(動画・録音)です。
- lb-phone のサーバーから https://nozawatec.com へ外向きに接続できる必要があります。
2026-10-25 に lb-phone v2.9.0 の配布物(暗号化されていない設定ファイル)で確かめた手順です。別の版では行の場所が違うことがあります。
提供元の資料を開く無料のスマホ
NPWD(New Phone Who Dis)
配布の 3.16.0 で手順を確認 · EdgeVault 側は同じ送りかたで検査済み · FiveM の実機は要確認リリース 3.16.0(2025-03-27。fxmanifest の表記は 3.15.1-beta.2) · 許諾: GPL-3.0
写真とボイスメッセージは、どちらも NPWD のサーバーが EdgeVault へ直接送ります。API キーはサーバーの設定(convar)だけに置き、プレイヤーには渡りません。書き換えるのは config.json と server.cfg です。
1. 写真の送り先 — config.json の images
images を次のように書き換えます。type はフォームの項目名として使われるので file にします。returnedDataIndexes は応答を順にたどる鍵で、EdgeVault の応答の data.url を指します。
"images": { "url": "https://nozawatec.com/api/edgeworks/vault/upload", "type": "file", "imageEncoding": "webp", "contentType": "multipart/form-data", "useContentType": false, "authorizationHeader": "X-API-Key", "authorizationPrefix": "", "useAuthorization": true, "returnedDataIndexes": ["data", "url"] },2. 置き場を許可する — config.json の imageSafety
imageSafety.safeImageUrls に nozawatec.com を足します。NPWD はホスト名の完全一致で比べるので、nozawatec.com をそのまま書いてください(EdgeVault の公開 URL は https://nozawatec.com/api/edgeworks/files/… です)。
"safeImageUrls": [ "nozawatec.com", "i.imgur.com", ...(元の行はそのまま) ]3. ボイスメッセージ — config.json の voiceMessage
使う場合だけ書き換えます。NPWD は録音の項目名(recording)を決め打ちにし、応答は入れ子でなく 1 段だけ読むので、returnedDataIndexes は ["url"] にします(EdgeVault は応答の一番上にも url を返します)。既定の url(https://api.fivemange/api/audio)は綴りが違っていて、そのままでは届きません。
"voiceMessage": { "enabled": true, "authorizationHeader": "X-API-Key", "url": "https://nozawatec.com/api/edgeworks/vault/upload", "returnedDataIndexes": ["url"] }4. 鍵を置く — server.cfg
EdgeWorks のダッシュボードで発行した API キーを、NPWD が読む 2 つの convar に入れます。必ず set を使ってください(setr にするとクライアントへ配られます)。screenshot-basic を npwd より前に ensure しておきます。
ensure screenshot-basic set SCREENSHOT_BASIC_TOKEN "EdgeWorks の API キー" set NPWD_AUDIO_TOKEN "EdgeWorks の API キー" ensure npwd5. 再起動して試す
サーバーを再起動し、カメラで撮った写真がギャラリーに出ること、EdgeWorks のダッシュボードの Vault に同じ写真が現れることを確かめます。失敗するとサーバーのコンソールに「Failed to upload photo, status code: …」が出ます。
気をつけること
- 写真もボイスメッセージも、NPWD のサーバーから送ります(撮影はクライアント、送信はサーバー)。API キーがプレイヤーに渡ることはありません。
- フォルダは指定できないので、EdgeVault の一番上(/)に入ります。
- ボイスメッセージは、NPWD が audio/ogg と名乗っても、EdgeVault は中身で種類を決めます(NPWD は録音の形式を指定していないので、中身が WebM なら video/webm として残ります)。
- ボイスメッセージを EdgeVault で受けるには、2026-10-25 以降の EdgeWorks が要ります(recording の項目名と、応答の一番上の url をこの日に足しました)。
- 大きさ: EdgeVault は 1 ファイル 100 MiB まで、全体の容量はプランごと(無料 10 GiB・Pro 100 GiB・Enterprise 300 GiB)です。
- 手順は配布の zip(npwd.zip)の中身で確かめています。ソースから建てた場合も config.json の形は同じです。
2026-10-25 に、公開されているソース(配布物)を取得して確かめた手順です。別の版では行の場所が違うことがあります。
提供元のリポジトリを開くqb-phone(QBCore)
1.5.0 のソースで手順を確認 · EdgeVault 側は同じ送りかたで検査済み · FiveM の実機は要確認1.5.0(qbcore-fivem/qb-phone のコミット 333e813・2026-08-24) · 許諾: GPL-3.0
カメラの写真を EdgeVault に置きます。qb-phone は既定で Discord の Webhook の URL をプレイヤーに渡し、プレイヤーの画面(screenshot-basic)から直接送らせます。これを、サーバーが撮影のたびに EdgeVault で使い切りの送信先を作って渡す形に書き換えます。API キーはサーバーの server.lua の中だけに置きます。
1. 送信先を作る — server.lua
冒頭の local FivemerrApiToken = '' の下に EdgeVaultApiKey を足し、qb-phone:server:GetWebhook のコールバックを丸ごと次に置き換えます。返すのは Webhook ではなく、撮影 1 回ぶんの送信先です。
local EdgeVaultApiKey = '' -- EdgeWorks の API キー(サーバーだけが読む) QBCore.Functions.CreateCallback('qb-phone:server:GetWebhook', function(_, cb) local function done(url) cb(url) end if EdgeVaultApiKey == '' then print('^1--- EdgeVault: set EdgeVaultApiKey in server.lua ---^7') return done(nil) end PerformHttpRequest('https://nozawatec.com/api/edgeworks/vault/presign', function(status, body) local okDecode, res = pcall(json.decode, body or '') local url = okDecode and type(res) == 'table' and res.success and res.data and res.data.upload_url_with_token if status ~= 200 or not url then print('^1--- EdgeVault: could not create an upload URL (HTTP ' .. tostring(status) .. ') ---^7') return done(nil) end done(url) end, 'POST', json.encode({ filename = 'qb-phone.jpg', mime_type = 'image/jpeg', folder = '/qb-phone' }), { ['Content-Type'] = 'application/json', ['X-API-Key'] = EdgeVaultApiKey, }) end)2. 送りかたと応答の読みかた — client.lua
カメラの処理の中の requestScreenshotUpload の呼び出し(項目名 'files[]'・Discord の形の応答を読む部分)を次に置き換えます。項目名を file にし、応答は EdgeVault の data.url を読みます。
exports['screenshot-basic']:requestScreenshotUpload(tostring(hook), 'file', function(data) SaveToInternalGallery() local ok, image = pcall(json.decode, data or '') local url = ok and type(image) == 'table' and image.data and image.data.url DestroyMobilePhone() CellCamActivate(false, false) if not url then QBCore.Functions.Notify('Upload failed', 'error') cb(json.encode({ url = nil })) takePhoto = false return end TriggerServerEvent('qb-phone:server:addImageToGallery', url) Wait(400) TriggerServerEvent('qb-phone:server:getImageFromGallery') cb(json.encode(url)) takePhoto = false end)3. Fivemerr は切ったまま — config.lua
Config.Fivemerr は false のままにします(Fivemerr の送りかたは画像を JSON の base64 で送るもので、EdgeVault はその形を受けません)。
4. 再起動して試す
screenshot-basic を qb-phone より前に ensure し、サーバーを再起動します。カメラで撮った写真がギャラリーに出ること、EdgeWorks のダッシュボードの Vault の /qb-phone に現れることを確かめます。
気をつけること
- 既定の作りでは、Discord の Webhook の URL が撮影のたびにプレイヤーへ渡ります(qb-phone:server:GetWebhook がクライアントへ返す)。この書き換えで、渡るのは 1 回だけ・1 時間有効の送信先になります。
- 写真は screenshot-basic の既定の JPEG です。
- 送信はプレイヤーの画面(screenshot-basic)から行うので、EdgeVault はその画面(https://cfx-nui-screenshot-basic)からの送信を受け付けます(2026-10-25 以降の EdgeWorks)。
- qb-phone は GPL-3.0 です。書き換えたものを配る場合は GPL-3.0 に従ってください(自分のサーバーで使うだけなら配布にはあたりません)。
2026-10-25 に、公開されているソース(配布物)を取得して確かめた手順です。別の版では行の場所が違うことがあります。
提供元のリポジトリを開くz-phone(QBCore・Qbox)
1.0.0 のソースで手順を確認 · EdgeVault 側は同じ送りかたで検査済み · FiveM の実機は要確認1.0.0(alfaben12/z-phone のコミット c6d1111・2025-01-15) · 許諾: 作者の独自の許諾(使用・改変は自由、販売は不可)
カメラの写真を EdgeVault に置きます。送りかたは qb-phone と同じで、既定では Discord の Webhook の URL をプレイヤーに渡しています。サーバーが撮影のたびに使い切りの送信先を作って渡す形に書き換えます。
1. 送信先を作る — server/main.lua
1 行目の local WebHook = '…' を EdgeVaultApiKey に置き換え、z-phone:server:GetWebhook の登録を丸ごと次に置き換えます。配布物の 1 行目には作者の Discord の Webhook の URL が入ったままなので、必ず消してください。
local EdgeVaultApiKey = '' -- EdgeWorks の API キー(サーバーだけが読む) lib.callback.register('z-phone:server:GetWebhook', function(_) if EdgeVaultApiKey == '' then print('^1--- EdgeVault: set EdgeVaultApiKey in server/main.lua ---^7') return nil end local p = promise.new() local function done(url) p:resolve(url) end PerformHttpRequest('https://nozawatec.com/api/edgeworks/vault/presign', function(status, body) local okDecode, res = pcall(json.decode, body or '') local url = okDecode and type(res) == 'table' and res.success and res.data and res.data.upload_url_with_token if status ~= 200 or not url then print('^1--- EdgeVault: could not create an upload URL (HTTP ' .. tostring(status) .. ') ---^7') return done(nil) end done(url) end, 'POST', json.encode({ filename = 'z-phone.jpg', mime_type = 'image/jpeg', folder = '/z-phone' }), { ['Content-Type'] = 'application/json', ['X-API-Key'] = EdgeVaultApiKey, }) return Citizen.Await(p) end)2. 送りかたと応答の読みかた — client/feature/camera.lua
requestScreenshotUpload の呼び出し(項目名 'files[]'・Discord の形の応答を読む部分)を次に置き換えます。
exports['screenshot-basic']:requestScreenshotUpload(tostring(hook), 'file', function(data) SaveToInternalGallery() local ok, image = pcall(json.decode, data or '') local url = ok and type(image) == 'table' and image.data and image.data.url DestroyMobilePhone() CellCamActivate(false, false) if not url then xCore.Notify('Upload failed', 'error', 3000) end cb(url) takePhoto = false end)3. 再起動して試す
screenshot-basic を z-phone より前に ensure し、サーバーを再起動します。カメラで撮った写真がスマホに出ること、EdgeWorks のダッシュボードの Vault の /z-phone に現れることを確かめます。
気をつけること
- 配布物の server/main.lua には、作者のものとみられる Discord の Webhook の URL が書かれたまま公開されています。そのまま使うと、撮った写真がその Webhook(他人のチャンネル)へ送られます。
- 写真は screenshot-basic の既定の JPEG です。送信はプレイヤーの画面(screenshot-basic)から行います(2026-10-25 以降の EdgeWorks が受け付けます)。
- z-phone の許諾は、使用と改変を認め、販売を認めていません。
2026-10-25 に、公開されているソース(配布物)を取得して確かめた手順です。別の版では行の場所が違うことがあります。
提供元のリポジトリを開くgcphone(N3MTV/gcphone)
無料 · つなぐ手順は載せていません最後の更新 2020-08-21(コミット 41f9ed9)
写真の送信先と項目名が、スマホの画面の設定(クライアント側の config)に書かれる作りで、応答も files[1].url の形に決め打ちです。EdgeVault の API キーをプレイヤーに渡さずにつなぐ道が無いので、手順を載せていません。2020 年から更新が止まっています(readme の表記は GPL v3)。
提供元のリポジトリを開く手順を確かめていないスマホ
GKSPHONE V2 / GKS Tablet
有料 · カスタム保存先の設定箇所を公開資料で確認 · 接続は要検証- gksphone/config/serverconfig.lua と gks-tablet/config/serverconfig.lua の Cfg.MediaService を customMedia にします。
- 同ファイルの Cfg.MediaServices.customMedia にある URL・フォーム項目・レスポンスパスを EdgeVault 契約に合わせます。設定キーの形は配布版のコメントを優先してください。
- 写真・動画・ボイスメモをそれぞれ送信し、スマホ内の表示と EdgeVault の一覧を確認します。鍵は serverconfig.lua のみに置きます。
Quasar Smartphone V3
有料 · 標準メディアの保存先変更は未確認- 公式資料にはカスタムアプリからギャラリー・カメラを選ぶブリッジが記載されています。標準カメラの保存先を任意の API に変える設定は、公開資料から確認できませんでした。
- 配布版に公開されたサーバー側のメディア橋渡しがある場合だけ、EdgeVault の契約に接続します。標準機能の連携済みとは扱わないでください。
YSeries V2
有料 · 配布版の公開設定を要確認- 配布版の公開設定とサーバー側のアップロード処理を確認してください。現時点では標準メディアの保存先を EdgeVault に切り替える手順を検証していません。
- URL、認証ヘッダー、フォーム名、応答パスを変更できる場合は下の契約に合わせ、画像・動画・音声を個別に試します。
CodeM mPhone
有料 · 配布版の公開設定を要確認- 利用中の mPhone の版を確認し、公開された設定やサーバー側のメディア処理から保存先を変更できるか調べてください。標準カメラと EdgeVault の接続は未検証です。
- 変更できる場合は下の EdgeVault 契約と照合します。クライアントに API キーを置かず、画像・動画・音声のそれぞれを実機で確認してください。
接続後の確認
テスト用の写真を撮り、スマホ内で開けることと、EdgeVault に同じファイルが現れることを確認します。動画と音声も別々に試してください。失敗時は電話スクリプトのサーバーログ、EdgeVault の応答コード、アップロード形式を確認します。