You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TrueLayer沙箱支付创建失败:请求缺失Tl-Signature头

TrueLayer沙箱支付创建失败:Tl-Signature header缺失报错

尝试创建TrueLayer沙箱支付时,明明已添加请求头,却始终收到401错误,提示**"Tl-Signature header value is missing from the request"**。以下是使用truelayer-signing库的NestJS代码及错误响应:

代码实现

import { Injectable } from "@nestjs/common";
const sdk = require('api')('@truelayer/v1.0#7nim1b17lbzalnne');
const sdk1 = require('api')('@truelayer/v1.0#xk1zcylftx71d3');
const tlSigning = require('truelayer-signing');

@Injectable()
export class AppService {

  async getData(){
    sdk.server('https://auth.truelayer-sandbox.com');
    try{
      let data = await sdk.generateAccessToken({
        grant_type: 'client_credentials',
        client_id: 'sandbox-{your id}',
        client_secret: '{your secret}',
        scope: 'payments'
      });
      console.log(data.data)
      const Idempotency = Math.random() * 1000;
      const tlSignature = tlSigning.sign({
        kid: '8ab13f4a-bccc-4c32-b8a8-c1861b377f8e',
        privateKeyPem: ["-----BEGIN EC PRIVATE KEY-----",{your private key},
"-----END EC PRIVATE KEY-----"].join('\n'),
        method: "POST",
        path: "/payments",
        headers: { "Idempotency-Key": Idempotency },
        body: '{"payment_method":{"type":"bank_transfer","provider_selection":{"type":"user_selected","filter":{"release_channel":"general_availability","customer_segments":["retail"]},"scheme_selection":{"type":"instant_only","allow_remitter_fee":false}},"beneficiary":{"type":"merchant_account","verification":{"type":"automated"}}},"amount_in_minor":1,"currency":"GBP"}',
      });
      console.log(tlSignature)
      let res = await sdk1.createPayment('{"payment_method":{"type":"bank_transfer","provider_selection":{"type":"user_selected","filter":{"release_channel":"general_availability","customer_segments":["retail"]},"scheme_selection":{"type":"instant_only","allow_remitter_fee":false}},"beneficiary":{"type":"merchant_account","verification":{"type":"automated"}}},"amount_in_minor":1,"currency":"GBP"}', {
        'Authorization': `Bearer ${data.data.access_token}`,
        'idempotency-key': Idempotency,
        'Tl-Signature': tlSignature,
        'content-type': 'application/json; charset=UTF-8',
      });
      console.log(res)
    }catch(err){
      console.log('error 123')
      console.log(err)
    }
      
    return { message: "Hello API" };
  }
}

错误响应

Error: Unauthorized
    at new FetchError (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/errors/fetchError.js:21:28)
    at APICore.<anonymous> (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:152:51)
    at step (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:44:23)
    at Object.next (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:25:53)
    at fulfilled (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:16:58)
    at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  status: 401,
  data: {
    type: 'https://docs.truelayer.com/docs/error-types#unauthenticated',
    title: 'Unauthenticated',
    status: 401,
    detail: 'Tl-Signature header value is missing from the request.',
    trace_id: '03bf6cb64bb262a2147fc79c15e3a3f6'
  },
  headers: HeadersList {
    cookies: null,
    [Symbol(headers map)]: Map(13) {
      'date' => [Object],
      'content-type' => [Object],
      'transfer-encoding' => [Object],
      'connection' => [Object],
      'tl-trace-id' => [Object],
      'referrer-policy' => [Object],
      'x-frame-options' => [Object],
      'x-content-type-options' => [Object],
      'strict-transport-security' => [Object],
      'content-security-policy' => [Object],
      'cf-cache-status' => [Object],
      'server' => [Object],
      'cf-ray' => [Object]
    },
    [Symbol(headers map sorted)]: null
  },
  res: Response {
    [Symbol(realm)]: null,
    [Symbol(state)]: {
      aborted: false,
      rangeRequested: false,
      timingAllowPassed: true,
      requestIncludesCredentials: true,
      type: 'default',
      status: 401,
      timingInfo: [Object],
      cacheState: '',
      statusText: 'Unauthorized',
      headersList: [HeadersList],
      urlList: [Array],
      body: [Object]
    },
    [Symbol(headers)]: HeadersList {
      cookies: null,
      [Symbol(headers map)]: [Map],
      [Symbol(headers map sorted)]: null
    }
  }
}
排查与解决办法

1. 修正SDK服务器配置

sdk1未指定沙箱服务器地址,可能默认指向了错误环境,需添加沙箱API地址:

sdk1.server('https://api.truelayer-sandbox.com');

2. 统一签名与请求的参数一致性

签名生成时的参数必须和实际请求完全匹配:

  • Idempotency-Key:将数值转为字符串,避免类型差异:
    const idempotencyKey = Math.random() * 1000 + '';
    // 签名时用字符串值
    headers: { "Idempotency-Key": idempotencyKey },
    // 请求头也用同一个字符串
    'Idempotency-Key': idempotencyKey,
    
  • 请求体:将body存为变量,签名和请求复用同一个值,避免字符差异:
    const paymentBody = '{"payment_method":{"type":"bank_transfer",...}}';
    // 签名时用paymentBody
    body: paymentBody,
    // 请求时也用paymentBody
    body: paymentBody,
    

3. 检查请求头传递方式

第三方SDK可能对请求头格式有特殊要求,可尝试用原生fetch替代SDK验证:

await fetch('https://api.truelayer-sandbox.com/payments', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${data.data.access_token}`,
    'Idempotency-Key': idempotencyKey,
    'Tl-Signature': tlSignature,
    'Content-Type': 'application/json'
  },
  body: paymentBody
});

4. 确认头名称大小写

确保请求头键名是'Tl-Signature',避免客户端自动转为小写(如tl-signature)导致服务端无法识别。


内容的提问来源于stack exchange,提问作者Sathesh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:35:07