Ir al contenido

API

En esta página

Crear

Crea un retiro desde un saldo en tokens hacia una billetera de la lista blanca, elige la red de salida, firma la petición y sigue su estado.

POST/v1/withdrawals

Clave de API: Payout

Un retiro es irreversible en cuanto la transacción se firma y se difunde a la cadena. Verifica destination_address y network antes de enviar: la petición aterriza en created y solo puede cancelarse hasta que arranca la ejecución, algo que puede ocurrir instantes después. Tras la difusión no hay vía de contracargo, y una dirección equivocada significa fondos perdidos.

Un retiro no espera a ninguna tanda: la ejecución arranca en cuanto se acepta la petición. Lo que tarde luego la transferencia en llegar es la velocidad de la red de salida con la carga que tenga en ese momento.

Cuerpo de la petición

Parámetro Tipo Obligatorio Descripción
amount string Importe del retiro como cadena decimal (por ejemplo, "100.00")
currency string Símbolo del activo cripto. Se puede retirar cualquier activo del que tengas saldo; las redes disponibles dependen del activo (consulta Monedas admitidas)
network string Código de la red de salida: TRC20, ERC20, BEP20, POLYGON, ARBITRUM, OPTIMISM, BASE, TON, AVAX, SOL o PLASMA. Son once de las trece redes que aceptan pagos: NEAR y SUI solo cobran, y una dirección suya no entra en la lista blanca (consulta Monedas admitidas)
destination_address string Dirección de la billetera de destino. Debe estar ya en la lista blanca de retiros de este comercio
external_order_id string Tu identificador de envío (máximo 200 caracteres), único por comercio. Sirve para la idempotencia: una repetición con el mismo valor devuelve el retiro existente en lugar de enviar de nuevo

Petición de ejemplo

{
  "amount": "100.00",
  "currency": "USDT",
  "network": "TRC20",
  "destination_address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
  "external_order_id": "payout-001"
}

Ejemplos de código

Cada pestaña usa un SDK oficial con una clave Payout. La firma, la serialización, los reintentos seguros y los errores tipados los resuelve el SDK.

API_KEY_ID="rk_live_xxxxxxxxxxxx"
API_SECRET="sk_live_xxxxxxxxxxxx"
BODY='{"destination_address":"TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9","network":"TRC20","currency":"USDT","amount":"50.00","external_order_id":"payout-123"}'

TS=$(date +%s)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | sed 's/^.* //')
SIGNATURE=$(printf '%s\n%s\n%s\n%s\n%s' "$TS" POST /v1/withdrawals '' "$BODY_HASH" \
  | openssl dgst -sha256 -hmac "$API_SECRET" -binary | base64)

curl -sS https://api.paymos.io/v1/withdrawals \
  -H "Authorization: HMAC-SHA256 $API_KEY_ID:$SIGNATURE" \
  -H "X-Request-Timestamp: $TS" \
  -H "Content-Type: application/json" \
  -d "$BODY"
import { Paymos, externalOrderId } from '@paymos/sdk';

const paymos = new Paymos({
  apiKey: process.env.PAYMOS_PAYOUT_KEY,
  apiSecret: process.env.PAYMOS_API_SECRET,
});
const withdrawal = await paymos.withdrawals.create({
  destinationAddress: 'TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9',
  network: 'TRC20',
  currency: 'USDT',
  amount: '50.00',
  externalOrderId: externalOrderId('payout'),
});

console.log(withdrawal.withdrawalId, withdrawal.status);
import os

from paymos import Paymos

paymos = Paymos(
    api_key=os.environ["PAYMOS_PAYOUT_KEY"],
    api_secret=os.environ["PAYMOS_API_SECRET"],
)
withdrawal = paymos.withdrawals.create(
    destination_address="TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
    network="TRC20",
    currency="USDT",
    amount="50.00",
    external_order_id="payout-001",
)

print(withdrawal["withdrawal_id"], withdrawal["status"])
<?php
use Paymos\Client;
use Paymos\ClientConfig;
use Paymos\IdempotencyKey;

$paymos = new Client(new ClientConfig(
    getenv('PAYMOS_PAYOUT_KEY'),
    getenv('PAYMOS_API_SECRET')
));
$withdrawal = $paymos->withdrawals()->create(array(
    'destination_address' => 'TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9',
    'network' => 'TRC20',
    'currency' => 'USDT',
    'amount' => '50.00',
    'external_order_id' => IdempotencyKey::externalOrderId('payout'),
));

echo $withdrawal['withdrawal_id'] . ' ' . $withdrawal['status'];
package main

import (
	"context"
	"fmt"
	"os"

	paymos "github.com/Paymos-labs/go-sdk/v2"
)

func main() {
	client, err := paymos.NewClient(os.Getenv("PAYMOS_PAYOUT_KEY"), os.Getenv("PAYMOS_API_SECRET"))
	if err != nil {
		panic(err)
	}
	withdrawal, err := client.Withdrawals.Create(context.Background(), paymos.CreateWithdrawalParams{
		DestinationAddress: "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
		Network:            "TRC20",
		Currency:           "USDT",
		Amount:             "50.00",
		ExternalOrderID:    "payout-001",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(withdrawal.WithdrawalID, withdrawal.Status)
}
using Paymos;

using var paymos = new PaymosClient(
    Environment.GetEnvironmentVariable("PAYMOS_PAYOUT_KEY")!,
    Environment.GetEnvironmentVariable("PAYMOS_API_SECRET")!);

var withdrawal = await paymos.Withdrawals.CreateAsync(new CreateWithdrawalRequest(
    DestinationAddress: "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
    Network: "TRC20",
    Currency: "USDT",
    Amount: "50.00",
    ExternalOrderId: "payout-001"));

Console.WriteLine($"{withdrawal.WithdrawalId} {withdrawal.Status}");
import io.paymos.CreateWithdrawalRequest;
import io.paymos.PaymosClient;
import io.paymos.Withdrawal;

PaymosClient paymos = new PaymosClient(
    System.getenv("PAYMOS_PAYOUT_KEY"),
    System.getenv("PAYMOS_API_SECRET"));

Withdrawal withdrawal = paymos.withdrawals.create(new CreateWithdrawalRequest(
    "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
    "TRC20",
    "USDT",
    "50.00",
    "payout-001"));

System.out.println(withdrawal.withdrawalId() + " " + withdrawal.status());
require 'paymos'

paymos = Paymos::Client.new(
  api_key: ENV.fetch('PAYMOS_PAYOUT_KEY'),
  api_secret: ENV.fetch('PAYMOS_API_SECRET')
)
withdrawal = paymos.withdrawals.create(
  destination_address: 'TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9',
  network: 'TRC20',
  currency: 'USDT',
  amount: '50.00',
  external_order_id: 'payout-001'
)

puts "#{withdrawal.withdrawal_id} #{withdrawal.status}"
use paymos::{CreateWithdrawalRequest, PaymosClient};

let paymos = PaymosClient::new(
    std::env::var("PAYMOS_PAYOUT_KEY")?,
    std::env::var("PAYMOS_API_SECRET")?,
)?;
let withdrawal = paymos
    .withdrawals()
    .create(&CreateWithdrawalRequest {
        destination_address: "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9".to_owned(),
        network: "TRC20".to_owned(),
        currency: "USDT".to_owned(),
        amount: "50.00".to_owned(),
        external_order_id: "payout-001".to_owned(),
    })
    .await?;

println!("{} {}", withdrawal.withdrawal_id, withdrawal.status);

Respuesta (201 Created / 200 si hay coincidencia idempotente)

{
  "withdrawal_id": "wdr_2M8K6Q4P9X1Z7A3B",
  "external_order_id": "payout-001",
  "status": "created",
  "is_final": false,
  "is_test": true,
  "amount": "100.00",
  "currency": "USDT",
  "network": "TRC20",
  "destination_address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
  "created_at": 1739289600
}

Campos de la respuesta

Campo Tipo Descripción
withdrawal_id string Identificador de retiro con prefijo (wdr_...)
external_order_id string Tu propia referencia de envío, devuelta tal cual desde la petición de creación
status string Estado del retiro (snake_case; consulta Estados del retiro)
is_final boolean true cuando el retiro ha alcanzado un estado final (completed, failed, cancelled)
is_test boolean true en retiros de Sandbox
amount string Importe del retiro
fee string? Comisión de red fija por token, resuelta desde el catálogo de tokens de la plataforma, en el mismo activo que amount. Es fija por token en lugar de una cotización de gas en vivo: se fija por debajo del coste de red de esa ruta y no lleva comisión de Paymos. Se omite cuando no hay comisión
currency string Símbolo del activo cripto
network string Código de la red blockchain
destination_address string Dirección de destino
tx_hash string? Hash en cadena de la transferencia que liquidó el envío. Solo se rellena cuando status es completed
explorer_url string? Enlace directo a tx_hash en el explorador de bloques de la red (por ejemplo, Tronscan o Etherscan). Solo se rellena cuando hay tx_hash y la red tiene un explorador configurado. Muéstralo tal cual como enlace pulsable
created_at integer Marca temporal Unix, en segundos
completed_at integer? Marca temporal Unix, en segundos. Se rellena cuando el envío se completa
failed_at integer? Marca temporal Unix, en segundos. Se rellena cuando el envío falla
cancelled_at integer? Marca temporal Unix, en segundos. Se rellena cuando el retiro se cancela

Idempotencia

Envía siempre external_order_id en un retiro. Repetir la misma llamada con el mismo external_order_id devuelve el retiro existente, nunca una segunda transferencia. El estado de la respuesta es 200 OK (sin cabecera Location) en una coincidencia idempotente y 201 Created en un retiro nuevo.

Es tu red de seguridad frente a redes inestables, procesos caídos y bucles de reintento. Usa el mismo identificador para el mismo envío y uno nuevo para uno distinto.

Errores

Consulta Códigos de error para el catálogo completo. La URI de type en cada respuesta de error enlaza directamente con la fila correspondiente.