개요
OptiRoutes의 모든 회사에는 전용 비공개 파일 폴더가 있습니다. 불러온 주문, 사진과 서명이 포함된 서명된 배송 확인서(POD), 경로 내보내기 파일, 일일 마감 보고서가 이 폴더에 저장됩니다. 파일 API를 사용하면 FTP 서버를 거치지 않고 귀사의 시스템이 이 폴더를 직접 읽고 쓸 수 있습니다.
- 주소:
https://srv2.optiroutes.com/api/v1— HTTPS만 지원합니다. - 접근: 회사 관리자가 OptiRoutes의 설정 → API 및 파일에서 직접 만드는 API 키입니다. OptiRoutes 지원팀에 요청할 필요가 없습니다.
- 모든 파일 형식을 지원합니다(현재 시스템에서 사용하는 형식): CSV, JSON, TXT, XLSX/XLS, PDF 및 이미지.
- 응답은 JSON입니다. 단, 파일 다운로드는 파일 자체를 반환합니다.
3단계로 시작하기
- 키를 만듭니다. OptiRoutes에서 관리자가 설정 → API 및 파일을 열고 새 키를 클릭한 뒤 이름(예: "ERP 서버")을 지정하고 권한을 선택한 다음 키를 복사합니다. 키는 한 번만 표시됩니다.
- 연결을 확인합니다.
curl -H "Authorization: Bearer $OPTIROUTES_KEY" https://srv2.optiroutes.com/api/v1/me - 오늘의 서명된 POD를 모두 내려받습니다. 하나의 ZIP 파일로 받습니다:
curl -H "Authorization: Bearer $OPTIROUTES_KEY" -o pod.zip "https://srv2.optiroutes.com/api/v1/pod/archive?date=$(date +%F)"
보안 — 꼭 읽어 주세요
- 키를 비밀번호처럼 다루세요. 시크릿 저장소 또는 서버의 환경 변수에 보관하세요. 웹 페이지, 모바일 앱, 이메일, 티켓, 소스 관리에는 절대 넣지 마세요.
- 최소 권한. 시스템마다 별도의 키를 만들고 필요한 권한만 부여하세요:
pod:read(서명된 POD만),files:read(회사의 모든 파일 읽기),files:write(주문 및 수신함 파일 업로드). - 주소를 제한하세요. 서버에 고정 IP 주소가 있다면 키에 추가하세요("허용 주소"). 그 외의 주소에서 오는 호출은 거부됩니다.
- 만료와 교체. 키는 지정한 일수 후에 만료되도록 설정할 수 있습니다. 교체하려면 새 키를 만들고, 시스템을 새 키로 전환한 다음, 이전 키를 폐기하세요. 중단 시간은 없습니다.
- 유출되었을 수 있는 키는 즉시 폐기하세요: 설정 → API 및 파일 → 키 폐기. 30초 이내에 작동이 중지됩니다.
- 감사. 모든 호출은 기록되며(시간, 주소, 파일, 응답), 같은 화면에서 관리자에게 표시됩니다.
- OptiRoutes는 각 키의 지문(SHA-256)만 보관하며 키 자체는 절대 보관하지 않습니다. 연결은 HTTPS(TLS 1.2 이상)만 허용됩니다.
- 키는 자사 폴더에만 접근할 수 있습니다. 다른 회사의 파일이나 시스템 내부 폴더에는 접근할 수 없습니다.
인증
모든 요청에서 다음 헤더 중 하나로 키를 보내세요:
Authorization: Bearer opr_2813_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or
X-API-Key: opr_2813_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx키는 opr_2813_… 형태입니다(회사 번호 뒤에 임의의 문자 32자).
회사 폴더
| 폴더 | 내용 | 작성 주체 |
|---|---|---|
orders_files/ | OptiRoutes가 불러오는 일일 주문 파일: orders_files/YYYY-MM-DD.csv(또는 .json / .TXT, 설정 → 주문 불러오기의 설정에 따름). 경로 내보내기: orders_files/routes_export_YYYY_MM_DD.csv. | 귀사(주문) · OptiRoutes(내보내기) |
pod/YYYY/MM/DD/ | 해당 날짜의 서명된 POD: <order>_sign_….pdf, 서명 및 사진(<order>_….png/jpg). | OptiRoutes |
pod/ | 기사 앱에서 서명할 원본 배송 확인서: pod/<order number>.pdf. | 귀사 |
reports/YYYY/MM/ | 일일 마감 보고서와 반품 보고서. | OptiRoutes |
podBaseFile/ | POD 기본 양식. | 귀사 |
inbox/ | 전달하려는 파일을 위한 자유 폴더. | 귀사 |
레퍼런스
| 호출 | 권한 | 기능 |
|---|---|---|
GET /api/v1/me | 모든 권한 | 키를 확인합니다. 회사 번호, 키의 권한, 귀사의 주소를 응답합니다. |
GET /api/v1/files?folder=<folder> | files:read (pod:read: pod/만) | 폴더 한 단계의 목록을 반환합니다: 파일(이름, 경로, 크기, 수정 시간)과 하위 폴더. |
GET /api/v1/files/download?path=<file> | files:read (pod:read: pod/만) | 파일 하나를 내려받습니다. |
PUT /api/v1/files?path=<file> | files:write | 파일을 업로드합니다(요청 본문이 파일이거나, file 필드가 있는 multipart 양식). 기존 파일은 교체됩니다. 최대 50 MB. |
DELETE /api/v1/files?path=<file> | files:write | 직접 업로드한 파일을 삭제합니다(업로드가 허용되는 위치에서). |
GET /api/v1/pod?date=YYYY-MM-DD[&order=<number>] | pod:read | 하루치 POD 파일을 주문 번호와 종류(signed_pdf, signature, photo)와 함께 반환합니다. |
GET /api/v1/pod/archive?date=YYYY-MM-DD[&kind=signed_pdf] | pod:read | 해당 날짜의 모든 POD 파일을 하나의 ZIP으로 반환합니다. |
목록 응답 예시:
{
"ok": true,
"folder": "pod/2026/10/11/",
"items": [
{ "name": "12345_sign_2026_10_11.pdf", "path": "pod/2026/10/11/12345_sign_2026_10_11.pdf",
"type": "file", "size": 84213, "modified": "2026-10-11T09:14:02.000Z" }
]
}자주 하는 작업
오늘의 주문 파일 업로드
# curl (Linux / macOS / Windows 10+)
curl -X PUT -H "Authorization: Bearer $OPTIROUTES_KEY" \
--data-binary @orders.csv -H "Content-Type: text/csv" \
"https://srv2.optiroutes.com/api/v1/files?path=orders_files/$(date +%F).csv"
# PowerShell
Invoke-RestMethod -Method Put -InFile .\orders.csv -ContentType 'text/csv' `
-Headers @{ Authorization = "Bearer $env:OPTIROUTES_KEY" } `
-Uri "https://srv2.optiroutes.com/api/v1/files?path=orders_files/$(Get-Date -f yyyy-MM-dd).csv"OptiRoutes는 현재와 같은 방식으로 파일을 불러옵니다(설정 → 주문 불러오기의 자동 불러오기 또는 사용자의 "파일 불러오기").
주문 하나의 서명된 POD 내려받기
curl -H "Authorization: Bearer $OPTIROUTES_KEY" "https://srv2.optiroutes.com/api/v1/pod?date=2026-10-11&order=12345"
# then, for each item:
curl -H "Authorization: Bearer $OPTIROUTES_KEY" -OJ "https://srv2.optiroutes.com/api/v1/files/download?path=pod/2026/10/11/12345_sign_2026_10_11.pdf"
일일 마감 보고서 내려받기
curl -H "Authorization: Bearer $OPTIROUTES_KEY" "https://srv2.optiroutes.com/api/v1/files?folder=reports/2026/10/"
curl -H "Authorization: Bearer $OPTIROUTES_KEY" -OJ "https://srv2.optiroutes.com/api/v1/files/download?path=reports/2026/10/report_2026_10_11.csv"
Python
import os, datetime, requests
BASE = "https://srv2.optiroutes.com/api/v1"
H = {"Authorization": f"Bearer {os.environ['OPTIROUTES_KEY']}"}
# upload today's orders
day = datetime.date.today().isoformat()
with open("orders.csv", "rb") as f:
r = requests.put(f"{BASE}/files", params={"path": f"orders_files/{day}.csv"},
data=f, headers={**H, "Content-Type": "text/csv"}, timeout=60)
r.raise_for_status()
# download every signed POD of the day
pods = requests.get(f"{BASE}/pod", params={"date": day}, headers=H, timeout=60).json()["items"]
for p in pods:
if p["kind"] == "signed_pdf":
data = requests.get(f"{BASE}/files/download", params={"path": p["path"]}, headers=H, timeout=60)
open(p["name"], "wb").write(data.content)
C# (.NET)
using var http = new HttpClient { BaseAddress = new Uri("https://srv2.optiroutes.com/api/v1/") };
http.DefaultRequestHeaders.Authorization =
new("Bearer", Environment.GetEnvironmentVariable("OPTIROUTES_KEY"));
// upload today's orders
var day = DateTime.Today.ToString("yyyy-MM-dd");
using var content = new ByteArrayContent(File.ReadAllBytes("orders.csv"));
content.Headers.ContentType = new("text/csv");
(await http.PutAsync($"files?path=orders_files/{day}.csv", content)).EnsureSuccessStatusCode();
// the day's PODs as one ZIP
var zip = await http.GetByteArrayAsync($"pod/archive?date={day}");
File.WriteAllBytes($"pod-{day}.zip", zip);
Node.js
const BASE = 'https://srv2.optiroutes.com/api/v1';
const H = { Authorization: `Bearer ${process.env.OPTIROUTES_KEY}` };
const day = new Date().toISOString().slice(0, 10);
// list and download the day's signed PODs (Node 18+)
const { items } = await (await fetch(`${BASE}/pod?date=${day}`, { headers: H })).json();
for (const p of items.filter((i) => i.kind === 'signed_pdf')) {
const res = await fetch(`${BASE}/files/download?path=${encodeURIComponent(p.path)}`, { headers: H });
await require('fs/promises').writeFile(p.name, Buffer.from(await res.arrayBuffer()));
}FTP처럼 사용하기 — 폴더 동기화 스크립트
FTP를 사용하던 팀은 자체 서버의 폴더를 회사 폴더와 동기화된 상태로 유지할 수 있습니다. 예약된 작업이 새 파일(예: POD)을 내려받고, 로컬 폴더에 넣어 둔 파일을 업로드합니다. 아래 PowerShell 스크립트가 두 가지를 모두 수행합니다. Windows 작업 스케줄러에서 몇 분마다 실행하세요(Linux에서는 cron과 curl 명령행을 사용하세요).
# optiroutes-sync.ps1 — download new PODs, upload what is in .\outbox (run every 5 minutes)
$Base = 'https://srv2.optiroutes.com/api/v1'
$H = @{ Authorization = "Bearer $env:OPTIROUTES_KEY" }
$Local = 'C:\OptiRoutes'
New-Item -ItemType Directory -Force "$Local\pod", "$Local\outbox", "$Local\sent" | Out-Null
# 1. today's and yesterday's PODs -> C:\OptiRoutes\pod\YYYY-MM-DD\
foreach ($d in (Get-Date), (Get-Date).AddDays(-1)) {
$day = $d.ToString('yyyy-MM-dd'); $dir = "$Local\pod\$day"
New-Item -ItemType Directory -Force $dir | Out-Null
$list = Invoke-RestMethod -Headers $H -Uri "$Base/pod?date=$day"
foreach ($f in $list.items) {
$dest = Join-Path $dir $f.name
if (-not (Test-Path $dest)) {
Invoke-WebRequest -Headers $H -OutFile $dest -Uri ("$Base/files/download?path=" + [uri]::EscapeDataString($f.path))
}
}
}
# 2. every file in C:\OptiRoutes\outbox -> orders_files/, then moved to C:\OptiRoutes\sent
Get-ChildItem "$Local\outbox" -File | ForEach-Object {
Invoke-RestMethod -Method Put -Headers $H -InFile $_.FullName -ContentType 'application/octet-stream' `
-Uri ("$Base/files?path=" + [uri]::EscapeDataString("orders_files/" + $_.Name)) | Out-Null
Move-Item $_.FullName "$Local\sent\" -Force
}회사를 FTP에서 API로 전환하기
관리자가 설정 → API 및 파일 → 회사 파일의 이동 방식: API(권장)에서 전환합니다. 그 시점부터 회사의 FTP로는 아무것도 전송되지 않으며, 모든 파일이 대신 회사 폴더에 저장됩니다:
| FTP 사용 시 | API 사용 시 |
|---|---|
| 주문 파일을 FTP에 올립니다 | PUT /api/v1/files?path=orders_files/YYYY-MM-DD.csv |
서명된 POD가 귀사 FTP의 /POD/로 전송됩니다 | GET /api/v1/pod?date=… / /api/v1/pod/archive?date=… |
경로 내보내기가 /orders/로 전송됩니다 | orders_files/routes_export_YYYY_MM_DD.csv |
보고서가 /orders/YYYY/MM/로 전송됩니다 | reports/YYYY/MM/ |
신규 회사는 처음부터 API로 운영합니다. FTP로 되돌리는 것도 같은 스위치로 합니다.
이전 OptiRoutes 서버를 사용하는 회사
아직 이전 OptiRoutes 서버(WEB)를 사용하는 회사도 서명된 POD에 대해서는 API를 사용할 수 있습니다. pod:read 권한이 있는 키를 만들고 /api/v1/pod, /api/v1/pod/archive, /api/v1/files/download?path=pod/…를 사용하세요. 그 외 파일은 새 서버로 전환할 때까지 현재와 같은 방식으로 전달됩니다.
오류
오류가 발생하면 {"ok": false, "error": "<code>", "message": "<explanation>"} 형태로 응답합니다.
| HTTP | error | 조치 |
|---|---|---|
| 401 | missing_key / invalid_key | 키를 보내세요. 키가 폐기되거나 만료되지 않았는지 확인하세요. |
| 403 | scope_missing | 키에 권한이 없습니다. 해당 권한이 있는 키를 만드세요. |
| 403 | ip_not_allowed | 허용된 주소에서 호출하거나 키의 주소를 업데이트하세요. |
| 403 | folder_read_only | orders_files/, inbox/, podBaseFile/ 또는 pod/<file>.pdf에만 업로드하세요. |
| 400 | invalid_path / invalid_date | 경로는 상대 경로(orders_files/a.csv)이며, 날짜는 YYYY-MM-DD 형식입니다. |
| 404 | not_found / no_pod_files | 해당 파일이 없습니다 / 해당 날짜에 POD가 없습니다. |
| 413 | file_too_large | 파일당 최대 50 MB입니다. |
| 429 | rate_limited | 1분 기다린 후 다시 시도하세요. |
| 502 / 503 | storage_unavailable / files_api_unavailable | 일시적인 오류입니다. 1분 후 다시 시도하세요. |
제한
- 키당 분당 요청 300건.
- 파일당 50 MB.
- 회사당 활성 키 20개.
- 폴더 목록은 최대 5,000개 항목을 반환합니다. 더 많은 항목이 필요하면 하위 폴더(예: POD 하루치)를 조회하세요.
도움말
회사 관리자는 설정 → API 및 파일에서 모든 키와 각 키의 마지막 사용 시간, 최근 호출을 확인할 수 있습니다. 그 밖의 문의는 회사 번호와 호출 시간을 알려 OptiRoutes 지원팀에 연락하세요. 키 자체는 절대 보내지 마세요.