在线商城Sage Accounting订单同步API自动化授权问题咨询
解决Sage API自动化获取Access Token的问题
我明白你现在卡在了Sage API OAuth流程的自动化上——因为获取授权码(code)需要手动登录Sage账户,这直接打断了订单同步脚本的自动化执行。其实Sage的OAuth机制支持离线访问模式,刚好能解决这个问题,咱们一步步来:
核心思路
先手动完成一次授权流程拿到refresh_token,之后脚本就可以完全依赖refresh_token自动刷新access_token,再也不需要手动登录了。
第一步:一次性手动获取初始授权码和Refresh Token
这一步只需要做一次,之后就彻底自动化:
- 构造授权URL,一定要带上
scope=offline_access参数(这是获取离线访问权限的关键),格式大概是:https://api.sage.com/oauth2/auth?client_id=你的客户端ID&redirect_uri=你的重定向URI&response_type=code&scope=offline_access - 在浏览器中打开这个URL,登录你的Sage账户并授权应用访问
- 授权成功后会跳转到你设置的重定向URI,从URL的查询参数里提取
code值 - 调用Sage的token接口,用这个
code换取access_token和refresh_token,把这两个值(尤其是refresh_token)安全存储起来(比如加密配置文件、环境变量,绝对不能硬编码)
第二步:脚本中自动用Refresh Token刷新Access Token
之后每次脚本需要调用Sage API时,按这个逻辑走:
- 先检查本地保存的
access_token是否过期(可以通过之前返回的expires_in时间判断) - 如果没过期,直接用它调用API创建发票
- 如果过期了,调用Sage的token刷新接口,传入
refresh_token、客户端ID、客户端密钥,获取新的access_token和refresh_token - 更新保存的
refresh_token(每次刷新可能会生成新的,一定要替换旧的),然后用新的access_token执行订单同步请求
关键注意事项
- 注册Sage应用时,一定要确保勾选了离线访问权限,否则拿不到
refresh_token refresh_token的有效期很长(通常几年),但如果过期了,你只需要再手动走一次第一步的授权流程即可- 所有敏感信息(客户端密钥、refresh_token)必须加密存储,绝对不能暴露在代码仓库或日志里
代码示例(Python)
这里给你一个简化的刷新token并创建发票的示例:
import requests import json from datetime import datetime, timedelta # 安全存储的配置信息 CLIENT_ID = "你的客户端ID" CLIENT_SECRET = "你的客户端密钥" REFRESH_TOKEN = "你保存的refresh_token" TOKEN_URL = "https://api.sage.com/oauth2/token" INVOICE_API_URL = "https://api.sage.com/accounting/v3/invoices" # 模拟存储token的本地文件(实际建议用加密存储) TOKEN_STORAGE = "sage_tokens.json" def load_saved_tokens(): try: with open(TOKEN_STORAGE, "r") as f: return json.load(f) except FileNotFoundError: return {"access_token": None, "expires_at": 0} def save_tokens(tokens): with open(TOKEN_STORAGE, "w") as f: json.dump(tokens, f) def get_valid_access_token(): saved_tokens = load_saved_tokens() current_time = datetime.now().timestamp() # 如果token未过期,直接返回 if saved_tokens["access_token"] and saved_tokens["expires_at"] > current_time: return saved_tokens["access_token"] # 否则用refresh_token刷新 payload = { "grant_type": "refresh_token", "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "refresh_token": REFRESH_TOKEN } response = requests.post(TOKEN_URL, data=payload) response.raise_for_status() token_data = response.json() # 计算过期时间并保存 expires_at = current_time + token_data["expires_in"] new_tokens = { "access_token": token_data["access_token"], "expires_at": expires_at } save_tokens(new_tokens) # 更新全局的refresh_token(如果返回了新的) global REFRESH_TOKEN if "refresh_token" in token_data: REFRESH_TOKEN = token_data["refresh_token"] # 这里可以额外保存新的refresh_token到更安全的地方 return token_data["access_token"] # 同步订单到Sage的主逻辑 def sync_order_to_sage(order_details): access_token = get_valid_access_token() headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } # 把你的订单详情转化为Sage要求的发票格式 sage_invoice_data = { "contact": {"id": order_details["customer_sage_id"]}, "date": datetime.now().strftime("%Y-%m-%d"), "due_date": (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d"), "lines": [ { "description": item["product_name"], "quantity": item["quantity"], "unit_price": item["price"] } for item in order_details["items"] ], "status": "draft" # 或者根据需求设置为其他状态 } response = requests.post(INVOICE_API_URL, json=sage_invoice_data, headers=headers) response.raise_for_status() print("订单同步成功,发票ID:", response.json()["id"]) # 调用示例(传入你的订单详情) # sample_order = { # "customer_sage_id": "SAGE客户ID", # "items": [{"product_name": "商品A", "quantity": 2, "price": 99.99}] # } # sync_order_to_sage(sample_order)
内容的提问来源于stack exchange,提问作者CiprianIvan
相关产品推荐
相关产品推荐

