Transaction Modes
Transaction Modes
Every write endpoint on the API takes a mode field with one of two values:
| Mode | Who signs | Who broadcasts | When to use |
|---|---|---|---|
unsigned (default) | The client | The client (via POST /v2/transactions) | User-facing actions; you control the keypair |
signed | The server (Privy platform wallet) | The server | Treasury / admin actions where the platform wallet is the authority |
Server-signed mode is gated by API-key scopes — for example, fees:claim is required to use mode=signed on the fee-claim endpoints. User-owned operations (airdrop claim, NFT stake/mint, gold lock) reject mode=signed because only the user wallet has authority to sign them.
unsigned flow
unsigned flowResponse body:
{
"data": {
"mode": "unsigned",
"transaction": "AQABAo...",
"required_signers": ["..."]
},
"meta": { "request_id": "req_…" }
}transaction is a base64 VersionedTransaction. If the endpoint generated ephemeral keypairs (e.g. POST /v2/tokens returns a mint_secret_key), they appear under required_signers — co-sign with both your wallet and any ephemeral key before submitting.
signed flow
signed flowResponse body:
{
"data": {
"mode": "signed",
"signature": "5kJ2…"
},
"meta": { "request_id": "req_…" }
}The signature has already been confirmed at confirmed commitment by the time you receive the response.
Which endpoints support which modes
| Endpoint | unsigned | signed | Required scope (signed) |
|---|---|---|---|
POST /v2/pools/{address}/fee-claims (any kind) | ✓ | ✓ | fees:claim |
POST /v2/airdrops | ✓ | ✓ | airdrop:admin |
POST /v2/airdrops/{id}/claims | ✓ | ✗ | n/a — claimer wallet must sign |
POST /v2/stakes | ✓ | ✗ | n/a — user wallet must sign |
DELETE /v2/stakes/{asset} | ✓ | ✗ | n/a |
POST /v2/nfts | ✓ | ✗ | n/a |
DELETE /v2/nfts/{asset} | ✓ | ✗ | n/a |
POST /v2/gold-locks | ✓ | ✗ | n/a |
DELETE /v2/gold-locks/{user} | ✓ | ✗ | n/a |
POST /v2/tokens | ✓ | ✗ | n/a |
DELETE /v2/tokens/{mint}/authorities/{type} | ✓ | ✗ | n/a |
Submitting an unsigned transaction
Once your client has signed the transaction, hand it to the API for broadcast via the unified transactions resource:
curl -X POST https://api.piratecrew.fun/v2/transactions \
-H "Authorization: Bearer $PIRATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "transaction": "<base64 signed tx>", "skip_preflight": false }'For multi-tx atomicity (e.g. a pool create + first buy), set bundle: true and pass an array of signed transactions:
curl -X POST https://api.piratecrew.fun/v2/transactions \
-H "Authorization: Bearer $PIRATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "bundle": true, "signed_transactions": ["<tx1>", "<tx2>"] }'Simulating before submitting
Polling status
curl https://api.piratecrew.fun/v2/transactions/$SIGNATURE \
-H "Authorization: Bearer $PIRATE_API_KEY"{
"data": {
"signature": "...",
"status": "confirmed",
"confirmation_status": "confirmed",
"err": null,
"slot": 271234567,
"confirmations": 12
},
"meta": { "request_id": "req_…" }
}status is the six-value lifecycle enum (unknown | submitted | processing | confirmed | finalized | failed) that most clients should branch on. The raw Solana confirmation_status is preserved for callers that need it. See Transaction Lifecycle for the full state machine and recommended polling pattern.