Wallet & Payments
Section titled “Wallet & Payments”The Wallet & Payments API exposes everything around an account’s money: balances (general and AI), the ledger of transactions, payment methods on file, top-up payments via Stripe and crypto providers, issued invoices, and the one-time GitHub connection bonus. Use these endpoints to render a wallet UI, top up an account, manage saved cards, fetch or download invoices, move funds between the general balance and AI credits, and reconcile settled payments.
All endpoints are scoped to the authenticated user. Money values are returned as 2-decimal USD strings unless the response field explicitly carries another type.
Balances
Section titled “Balances”GET /api/v1/wallet/balances
Section titled “GET /api/v1/wallet/balances”Return the aggregate balances for the authenticated user: the general balance plus the AI credit pool (limit, usage, remaining, reserved, usage status).
This endpoint takes no parameters.
curl -X GET 'https://api.hoody.com/api/v1/wallet/balances' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getBalances();{ "statusCode": 200, "message": "Balances retrieved successfully", "data": { "general_balance": "125.50", "ai_limit": "50.00", "ai_usage": "23.45", "ai_remaining": "26.55", "ai_reserved": "0.00", "ai_usage_status": "live" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/balances/ai
Section titled “GET /api/v1/wallet/balances/ai”Return only the AI credit pool: limit, usage, remaining, reserved, and usage status.
This endpoint takes no parameters.
curl -X GET 'https://api.hoody.com/api/v1/wallet/balances/ai' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getCredits();{ "statusCode": 200, "message": "AI balance retrieved successfully", "data": { "ai_limit": "50.00", "ai_usage": "23.45", "ai_remaining": "26.55", "ai_reserved": "0.00", "ai_usage_status": "live" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/balances/general
Section titled “GET /api/v1/wallet/balances/general”Return only the general (spendable) balance and its ledger record.
This endpoint takes no parameters.
curl -X GET 'https://api.hoody.com/api/v1/wallet/balances/general' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getBalance();{ "statusCode": 200, "message": "General balance retrieved successfully", "data": { "id": "507f1f77bcf86cd799439100", "user_id": "507f1f77bcf86cd799439011", "general_balance": "125.50", "created_at": "2025-01-10T08:30:00.000Z", "updated_at": "2025-01-21T20:00:00.000Z" }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/ai-fee-history
Section titled “GET /api/v1/wallet/ai-fee-history”Return a paginated list of platform fees charged on AI credit transfers and admin credits, newest first.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | No | Page number for pagination. Default: 1. |
limit | query | integer | No | Number of records per page. Default: 20. |
sort_by | query | string | No | One of "created_at", "amount", "transaction_id". Default: "created_at". |
sort_order | query | string | No | One of "asc", "desc". Default: "desc". |
curl -X GET 'https://api.hoody.com/api/v1/wallet/ai-fee-history?page=1&limit=20' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
for await (const fee of client.api.wallet.listCreditFeesIterator({ page: 1, limit: 20 })) { console.log(fee);}{ "statusCode": 200, "message": "Fees retrieved successfully", "data": { "fees": [ { "id": "507f1f77bcf86cd799439200", "transaction_id": "507f1f77bcf86cd799439110", "amount": "1.25", "created_at": "2025-01-21T20:30:00.000Z", "transaction": { "id": "507f1f77bcf86cd799439110", "reason": "ai_credit_topup", "amount": "25.00" } } ], "pagination": { "total": 1, "page": 1, "limit": 20, "totalPages": 1 } }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Transactions
Section titled “Transactions”GET /api/v1/wallet/transactions
Section titled “GET /api/v1/wallet/transactions”List wallet transactions for the authenticated user, newest first.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | No | Number of records to return. Default: 20. |
sort_by | query | string | No | One of "id", "transaction_type", "status", "amount", "created_at", "updated_at". Default: "created_at". |
sort_order | query | string | No | One of "asc", "desc". Default: "desc". |
page | query | integer | No | Page number, starting from 1. |
filter | query | string | No | Optional JSON object of column filters, e.g. {"status":"completed"} or {"amount":{"gte":10}}. A plain value matches exactly; an object applies operators eq, ne, gt, gte, lt, lte, like (case-insensitive substring; % and _ in the value are wildcards) and in (array, at most 100 values). Columns: transaction_type, status, amount, currency, reason, created_at, updated_at. Any other column or operator, a value that is not a string, number, boolean or null, or a filter that is not a JSON object is rejected with 400. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/transactions?limit=20' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
for await (const tx of client.api.wallet.listTransactionsIterator({ limit: 20 })) { console.log(tx);}Default response containing the requested wallet transactions.
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/transactions/{id}
Section titled “GET /api/v1/wallet/transactions/{id}”Fetch a single transaction by id.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Transaction id. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/transactions/507f1f77bcf86cd799439110' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getTransaction('507f1f77bcf86cd799439110');Default response containing the requested transaction.
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Transfers
Section titled “Transfers”POST /api/v1/wallet/transfers
Section titled “POST /api/v1/wallet/transfers”One-way transfer from the general balance to AI credits. The amount is debited from general, the platform fee is deducted, and the net amount is credited to the AI credit limit.
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | USD amount as a string with up to 2 decimals (e.g. "10.00"). No exponent, no negatives. |
idempotency_key | string | No | Optional caller idempotency key (1-128 chars, must contain a non-whitespace character). Retrying with the same key and same amount returns the original receipt without moving funds again; the same key with a different amount is rejected. |
expected_fee_bps | integer | No | Optional: the platform fee (basis points) the client displayed at confirmation. If it no longer matches the current server fee, the transfer is rejected so the user re-confirms. |
curl -X POST 'https://api.hoody.com/api/v1/wallet/transfers' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "amount": "25.00", "expected_fee_bps": 500 }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.transferToCredits({ amount: '25.00', expected_fee_bps: 500,});{ "statusCode": 200, "message": "Transfer completed and AI credit limit synced", "data": { "gross_transferred": "25.00", "net_ai_credit": "23.75", "fee": "1.25", "general_balance": "100.50", "ai_balance": "75.00", "key_created": false, "limit_sync_pending": false, "replayed": false }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Payment Methods
Section titled “Payment Methods”GET /api/v1/wallet/payment-methods/
Section titled “GET /api/v1/wallet/payment-methods/”List every payment method on file for the authenticated user. Default method first, then by newest created.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | No | Page number, starting from 1. Default: 1. |
limit | query | integer | No | Results per page. Capped at 100. Default: 100. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/payment-methods/?page=1&limit=100' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
for await (const pm of client.api.wallet.listPaymentMethodsIterator({ page: 1, limit: 100 })) { console.log(pm);}{ "statusCode": 200, "message": "Payment methods retrieved successfully", "data": [ { "id": "507f1f77bcf86cd799439130", "user_id": "507f1f77bcf86cd799439011", "type": "credit_card", "name": "Visa ending in 4242", "status": "active", "details": { "last4": "4242", "brand": "visa", "exp_month": 12, "exp_year": 2026 }, "is_default": true, "created_at": "2025-01-15T10:00:00.000Z", "updated_at": "2025-01-15T10:00:00.000Z" } ], "metadata": { "total": 1, "page": 1, "limit": 100, "pages": 1 }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/payment-methods/{id}
Section titled “GET /api/v1/wallet/payment-methods/{id}”Fetch a single payment method by id.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Payment method id. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/payment-methods/507f1f77bcf86cd799439130' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getPaymentMethod('507f1f77bcf86cd799439130');{ "statusCode": 200, "message": "Payment method retrieved successfully", "data": { "id": "507f1f77bcf86cd799439130", "user_id": "507f1f77bcf86cd799439011", "type": "credit_card", "name": "Visa ending in 4242", "status": "active", "details": { "last4": "4242", "brand": "visa", "exp_month": 12, "exp_year": 2026 }, "is_default": true, "created_at": "2025-01-15T10:00:00.000Z", "updated_at": "2025-01-15T10:00:00.000Z" }}{ "statusCode": 404, "error": "Not Found", "message": "Payment method not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
POST /api/v1/wallet/payment-methods/
Section titled “POST /api/v1/wallet/payment-methods/”Add a new payment method to the authenticated user’s account.
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
type | string | Yes | One of "credit_card", "paypal", "bank_transfer", "crypto". |
name | string | Yes | Human-readable label shown in the wallet UI. |
details | object | No | Provider-specific card details (for example last4, brand, exp_month, exp_year). |
is_default | boolean | No | Set this method as the default. |
curl -X POST 'https://api.hoody.com/api/v1/wallet/payment-methods/' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "type": "credit_card", "name": "Mastercard ending in 5555", "details": { "last4": "5555", "brand": "mastercard", "exp_month": 8, "exp_year": 2027 }, "is_default": false }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.createPaymentMethod({ type: 'credit_card', name: 'Mastercard ending in 5555', details: { last4: '5555', brand: 'mastercard', exp_month: 8, exp_year: 2027, }, is_default: false,});{ "statusCode": 201, "message": "Payment method added successfully", "data": { "id": "507f1f77bcf86cd799439131", "user_id": "507f1f77bcf86cd799439011", "type": "credit_card", "name": "Mastercard ending in 5555", "status": "active", "details": { "last4": "5555", "brand": "mastercard", "exp_month": 8, "exp_year": 2027 }, "is_default": false, "created_at": "2025-01-21T20:30:00.000Z", "updated_at": "2025-01-21T20:30:00.000Z" }}{ "statusCode": 400, "error": "Bad Request", "message": "type and name are required"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
PUT /api/v1/wallet/payment-methods/{id}
Section titled “PUT /api/v1/wallet/payment-methods/{id}”Update an existing payment method. All body fields are optional; only fields you send are changed.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Payment method id. |
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
name | string | No | Display name, at most 100 characters. |
details | object | No | Replace the provider-specific card details. |
status | string | No | One of "active", "inactive". |
is_default | boolean | No | Make this method the default. |
curl -X PUT 'https://api.hoody.com/api/v1/wallet/payment-methods/507f1f77bcf86cd799439131' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "name": "Mastercard (primary)", "status": "active", "is_default": true }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.updatePaymentMethod('507f1f77bcf86cd799439131', { name: 'Mastercard (primary)', status: 'active', is_default: true,});{ "statusCode": 200, "message": "Payment method updated successfully", "data": { "id": "507f1f77bcf86cd799439131", "user_id": "507f1f77bcf86cd799439011", "type": "credit_card", "name": "Mastercard (primary)", "status": "active", "details": { "last4": "5555", "brand": "mastercard", "exp_month": 10, "exp_year": 2027 }, "is_default": true, "created_at": "2025-01-21T20:30:00.000Z", "updated_at": "2025-01-21T20:45:00.000Z" }}{ "statusCode": 404, "error": "Not Found", "message": "Payment method not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
PATCH /api/v1/wallet/payment-methods/{id}
Section titled “PATCH /api/v1/wallet/payment-methods/{id}”HTTP method variant of PUT /api/v1/wallet/payment-methods/{id}. Same request body and same responses; use whichever verb your client prefers.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Payment method id. |
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
name | string | No | Display name, at most 100 characters. |
details | object | No | Replace the provider-specific card details. |
status | string | No | One of "active", "inactive". |
is_default | boolean | No | Make this method the default. |
curl -X PATCH 'https://api.hoody.com/api/v1/wallet/payment-methods/507f1f77bcf86cd799439131' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "name": "Mastercard (primary)", "status": "active", "is_default": true }'{ "statusCode": 200, "message": "Payment method updated successfully", "data": { "id": "507f1f77bcf86cd799439131", "user_id": "507f1f77bcf86cd799439011", "type": "credit_card", "name": "Mastercard (primary)", "status": "active", "details": { "last4": "5555", "brand": "mastercard", "exp_month": 10, "exp_year": 2027 }, "is_default": true, "created_at": "2025-01-21T20:30:00.000Z", "updated_at": "2025-01-21T20:45:00.000Z" }}{ "statusCode": 404, "error": "Not Found", "message": "Payment method not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
PUT /api/v1/wallet/payment-methods/{id}/default
Section titled “PUT /api/v1/wallet/payment-methods/{id}/default”Mark an existing payment method as the user’s default.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Payment method id. |
curl -X PUT 'https://api.hoody.com/api/v1/wallet/payment-methods/507f1f77bcf86cd799439131/default' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.setDefaultPaymentMethod('507f1f77bcf86cd799439131');{ "statusCode": 200, "message": "Default payment method set successfully", "data": { "id": "507f1f77bcf86cd799439131", "user_id": "507f1f77bcf86cd799439011", "type": "credit_card", "name": "Mastercard (primary)", "status": "active", "details": { "last4": "5555", "brand": "mastercard", "exp_month": 10, "exp_year": 2027 }, "is_default": true, "created_at": "2025-01-21T20:30:00.000Z", "updated_at": "2025-01-21T21:00:00.000Z" }}{ "statusCode": 404, "error": "Not Found", "message": "Payment method not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
PATCH /api/v1/wallet/payment-methods/{id}/default
Section titled “PATCH /api/v1/wallet/payment-methods/{id}/default”HTTP method variant of PUT /api/v1/wallet/payment-methods/{id}/default. Same path, same response, same effect.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Payment method id. |
curl -X PATCH 'https://api.hoody.com/api/v1/wallet/payment-methods/507f1f77bcf86cd799439131/default' \ -H 'Authorization: Bearer <token>'{ "statusCode": 200, "message": "Default payment method set successfully", "data": { "id": "507f1f77bcf86cd799439131", "user_id": "507f1f77bcf86cd799439011", "type": "credit_card", "name": "Mastercard (primary)", "status": "active", "details": { "last4": "5555", "brand": "mastercard", "exp_month": 10, "exp_year": 2027 }, "is_default": true, "created_at": "2025-01-21T20:30:00.000Z", "updated_at": "2025-01-21T21:00:00.000Z" }}{ "statusCode": 404, "error": "Not Found", "message": "Payment method not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
DELETE /api/v1/wallet/payment-methods/{id}
Section titled “DELETE /api/v1/wallet/payment-methods/{id}”Delete a payment method from the user’s account.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Payment method id. |
curl -X DELETE 'https://api.hoody.com/api/v1/wallet/payment-methods/507f1f77bcf86cd799439131' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.deletePaymentMethod('507f1f77bcf86cd799439131');{ "statusCode": 200, "message": "Payment method deleted successfully"}{ "statusCode": 404, "error": "Not Found", "message": "Payment method not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Invoices
Section titled “Invoices”GET /api/v1/wallet/invoices/
Section titled “GET /api/v1/wallet/invoices/”List the authenticated user’s invoices, paginated.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | No | Page number for pagination. Starts from 1. Default: 1. |
limit | query | integer | No | Number of invoices to return per page. Maximum 100. Default: 20. |
sort_by | query | string | No | One of id, invoice_number, status, amount, currency, issue_date, due_date, paid_date, created_at, updated_at, user_id, transaction_id. Unrecognised values fall back to created_at. |
sort_order | query | string | No | One of "asc", "desc". Default: "desc". |
filter | query | string | No | JSON object string filtering by the sortable fields, e.g. {"status":"paid"} or {"amount":{"gte":10}}. Operators: eq, ne, gt, gte, lt, lte, like, in. Unknown fields or operators are rejected with 400. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/invoices/?page=1&limit=20&sort_by=created_at&sort_order=desc' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
for await (const inv of client.api.wallet.listInvoicesIterator({ page: 1, limit: 20 })) { console.log(inv);}{ "statusCode": 200, "message": "Invoices retrieved successfully", "data": { "invoices": [ { "id": "507f1f77bcf86cd799439120", "user_id": "507f1f77bcf86cd799439011", "transaction_id": "507f1f77bcf86cd799439110", "invoice_number": "INV-1785439290709-4e2a8002866b32d1f473ffe0", "status": "paid", "amount": 50, "currency": "USD", "issue_date": "2025-01-20T15:30:00.000Z", "due_date": "2025-02-20T15:30:00.000Z", "paid_date": "2025-01-20T15:30:00.000Z", "created_at": "2025-01-20T15:30:00.000Z", "updated_at": "2025-01-20T15:30:00.000Z", "transaction": { "id": "507f1f77bcf86cd799439110", "transaction_type": "payment", "status": "completed", "amount": 50, "currency": "USD", "created_at": "2025-01-20T15:30:00.000Z" } } ], "pagination": { "total": 23, "page": 1, "limit": 10, "totalPages": 3 } }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/invoices/{id}
Section titled “GET /api/v1/wallet/invoices/{id}”Fetch a single invoice by id, including its billing details and line items.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Invoice id. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/invoices/507f1f77bcf86cd799439120' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getInvoice('507f1f77bcf86cd799439120');{ "statusCode": 200, "message": "Invoice retrieved successfully", "data": { "id": "507f1f77bcf86cd799439120", "user_id": "507f1f77bcf86cd799439011", "transaction_id": "507f1f77bcf86cd799439110", "invoice_number": "INV-1785439290709-4e2a8002866b32d1f473ffe0", "status": "paid", "amount": 50, "currency": "USD", "billing_details": { "payment_method": "Card (Stripe Checkout)", "payment_method_type": "card" }, "items": [ { "type": "general", "description": "Credits", "amount": 50 } ], "issue_date": "2025-01-20T15:30:00.000Z", "due_date": "2025-02-20T15:30:00.000Z", "paid_date": "2025-01-20T15:30:00.000Z", "created_at": "2025-01-20T15:30:00.000Z", "updated_at": "2025-01-20T15:30:00.000Z", "transaction": { "id": "507f1f77bcf86cd799439110", "transaction_type": "payment", "status": "completed", "amount": 50, "currency": "USD", "created_at": "2025-01-20T15:30:00.000Z" } }}{ "statusCode": 404, "error": "Not Found", "message": "Invoice not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/invoices/{id}/pdf
Section titled “GET /api/v1/wallet/invoices/{id}/pdf”Download an invoice as a PDF file (application/pdf).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Invoice id. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/invoices/507f1f77bcf86cd799439120/pdf' \ -H 'Authorization: Bearer <token>' \ -o invoice.pdfimport { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const pdf = await client.api.wallet.downloadInvoice('507f1f77bcf86cd799439120');Binary PDF body. Save the response to a file or stream it to the browser with Content-Disposition: attachment.{ "statusCode": 404, "error": "Not Found", "message": "Invoice not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
POST /api/v1/wallet/invoices/generate/{id}
Section titled “POST /api/v1/wallet/invoices/generate/{id}”Generate an invoice for a specific transaction. If an invoice already exists for the transaction, the existing invoice is returned with status 200.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Transaction id. |
curl -X POST 'https://api.hoody.com/api/v1/wallet/invoices/generate/507f1f77bcf86cd799439110' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.createInvoice('507f1f77bcf86cd799439110');{ "statusCode": 200, "message": "Invoice already exists", "data": { "invoice_id": "507f1f77bcf86cd799439120", "invoice_number": "INV-1785439290709-4e2a8002866b32d1f473ffe0" }}{ "statusCode": 201, "message": "Invoice generated successfully", "data": { "invoice_id": "507f1f77bcf86cd799439121", "invoice_number": "INV-1785439290812-9c6a2b1f4d0e88a37bb51c02" }}{ "statusCode": 404, "error": "Not Found", "message": "Transaction not found"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Payments
Section titled “Payments”GET /api/v1/wallet/payment-availability
Section titled “GET /api/v1/wallet/payment-availability”Report which top-up providers are usable right now (enabled and configured), the per-top-up USD bounds, and the AI credit transfer fee in basis points. No secrets are returned. Use this in the wallet UI to render the correct top-up affordance.
This endpoint takes no parameters.
curl -X GET 'https://api.hoody.com/api/v1/wallet/payment-availability' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getPaymentAvailability();{ "statusCode": 200, "message": "Payment availability retrieved successfully", "data": { "stripe": { "enabled": true, "min_usd": 5, "max_usd": 10000 }, "nowpayments": { "enabled": false, "min_usd": 5, "max_usd": 10000 }, "ai_credit_fee_bps": 0 }}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
POST /api/v1/wallet/payments/stripe/checkout
Section titled “POST /api/v1/wallet/payments/stripe/checkout”Create a payment intent and a hosted Stripe Checkout session. Redirect the user to the returned checkout_url. The wallet is credited only after Stripe confirms settlement via webhook.
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | USD amount as a strict decimal string (e.g. "25" or "25.00"). |
idempotency_key | string | No | Optional caller idempotency key (1-128 chars, must contain a non-whitespace character). Repeats with the same key return the original intent. |
curl -X POST 'https://api.hoody.com/api/v1/wallet/payments/stripe/checkout' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "amount": "25.00", "idempotency_key": "topup-2026-06-10-001" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.createStripeCheckout({ amount: '25.00', idempotency_key: 'topup-2026-06-10-001',});{ "statusCode": 201, "message": "Checkout session created", "data": { "intent": { "id": "665f1f77bcf86cd799439011", "provider": "stripe", "status": "pending", "amount": 25, "currency": "USD", "redirect_url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3", "credited_at": null, "expires_at": "2026-06-11T12:00:00.000Z", "created_at": "2026-06-10T12:00:00.000Z", "updated_at": "2026-06-10T12:00:00.000Z" }, "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3" }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYMENT_PROVIDER_UNAVAILABLE | Payment provider unavailable | This payment method is switched off or its provider could not be reached, so nothing was charged | Try again later or use another payment method |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/payments/stripe/intents
Section titled “GET /api/v1/wallet/payments/stripe/intents”List the authenticated user’s Stripe (card) payment intents, newest first.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | No | Maximum number of intents to return. Default: 20. |
offset | query | integer | No | Number of intents to skip from the start of the list. Default: 0. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/payments/stripe/intents?limit=20&offset=0' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.listStripePaymentIntents({ limit: 20, offset: 0 });{ "statusCode": 200, "message": "Payment intents retrieved successfully", "data": { "intents": [ { "id": "665f1f77bcf86cd799439011", "provider": "stripe", "status": "pending", "amount": 25, "currency": "USD", "redirect_url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3", "credited_at": null, "expires_at": "2026-06-11T12:00:00.000Z", "created_at": "2026-06-10T12:00:00.000Z", "updated_at": "2026-06-10T12:00:00.000Z" } ], "total": 1 }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYMENT_PROVIDER_UNAVAILABLE | Payment provider unavailable | This payment method is switched off or its provider could not be reached, so nothing was charged | Try again later or use another payment method |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/payments/stripe/intents/{id}
Section titled “GET /api/v1/wallet/payments/stripe/intents/{id}”Fetch one of the authenticated user’s Stripe payment intents. Poll this after the checkout redirect to confirm settlement.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Stripe payment intent id. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/payments/stripe/intents/665f1f77bcf86cd799439011' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getStripePaymentIntent('665f1f77bcf86cd799439011');{ "statusCode": 200, "message": "Payment intent retrieved successfully", "data": { "id": "665f1f77bcf86cd799439011", "provider": "stripe", "status": "pending", "amount": 25, "currency": "USD", "redirect_url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3", "credited_at": null, "expires_at": "2026-06-11T12:00:00.000Z", "created_at": "2026-06-10T12:00:00.000Z", "updated_at": "2026-06-10T12:00:00.000Z" }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYMENT_PROVIDER_UNAVAILABLE | Payment provider unavailable | This payment method is switched off or its provider could not be reached, so nothing was charged | Try again later or use another payment method |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
POST /api/v1/wallet/payments/crypto/invoice
Section titled “POST /api/v1/wallet/payments/crypto/invoice”Create a payment intent and a hosted crypto payment invoice (NOWPayments). Redirect the user to the returned invoice_url. The wallet is credited only after the provider confirms settlement via IPN.
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | USD amount as a strict decimal string (e.g. "25" or "25.00"). |
idempotency_key | string | No | Optional caller idempotency key (1-128 chars, must contain a non-whitespace character). Repeats with the same key return the original intent. |
curl -X POST 'https://api.hoody.com/api/v1/wallet/payments/crypto/invoice' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "amount": "25.00", "idempotency_key": "topup-2026-06-10-002" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.createCryptoInvoice({ amount: '25.00', idempotency_key: 'topup-2026-06-10-002',});{ "statusCode": 201, "message": "Crypto payment invoice created", "data": { "intent": { "id": "665f1f77bcf86cd799439012", "provider": "nowpayments", "status": "pending", "amount": 25, "currency": "USD", "redirect_url": "https://nowpayments.io/payment/?iid=4522625843", "credited_at": null, "expires_at": null, "created_at": "2026-06-10T12:00:00.000Z", "updated_at": "2026-06-10T12:00:00.000Z" }, "invoice_url": "https://nowpayments.io/payment/?iid=4522625843" }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYMENT_PROVIDER_UNAVAILABLE | Payment provider unavailable | This payment method is switched off or its provider could not be reached, so nothing was charged | Try again later or use another payment method |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/payments/crypto/intents
Section titled “GET /api/v1/wallet/payments/crypto/intents”List the authenticated user’s crypto payment intents, newest first.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | No | Maximum number of intents to return. Default: 20. |
offset | query | integer | No | Number of intents to skip from the start of the list. Default: 0. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/payments/crypto/intents?limit=20&offset=0' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.listCryptoPaymentIntents({ limit: 20, offset: 0 });{ "statusCode": 200, "message": "Payment intents retrieved successfully", "data": { "intents": [ { "id": "665f1f77bcf86cd799439012", "provider": "nowpayments", "status": "pending", "amount": 25, "currency": "USD", "redirect_url": "https://nowpayments.io/payment/?iid=4522625843", "credited_at": null, "expires_at": null, "created_at": "2026-06-10T12:00:00.000Z", "updated_at": "2026-06-10T12:00:00.000Z" } ], "total": 1 }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYMENT_PROVIDER_UNAVAILABLE | Payment provider unavailable | This payment method is switched off or its provider could not be reached, so nothing was charged | Try again later or use another payment method |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GET /api/v1/wallet/payments/crypto/intents/{id}
Section titled “GET /api/v1/wallet/payments/crypto/intents/{id}”Fetch one of the authenticated user’s crypto payment intents. Poll this after the invoice redirect to confirm settlement.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Crypto payment intent id. |
curl -X GET 'https://api.hoody.com/api/v1/wallet/payments/crypto/intents/665f1f77bcf86cd799439012' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getCryptoPaymentIntent('665f1f77bcf86cd799439012');{ "statusCode": 200, "message": "Payment intent retrieved successfully", "data": { "id": "665f1f77bcf86cd799439012", "provider": "nowpayments", "status": "pending", "amount": 25, "currency": "USD", "redirect_url": "https://nowpayments.io/payment/?iid=4522625843", "credited_at": null, "expires_at": null, "created_at": "2026-06-10T12:00:00.000Z", "updated_at": "2026-06-10T12:00:00.000Z" }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
PAYMENT_PROVIDER_UNAVAILABLE | Payment provider unavailable | This payment method is switched off or its provider could not be reached, so nothing was charged | Try again later or use another payment method |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
GitHub Connection Bonus
Section titled “GitHub Connection Bonus”GET /api/v1/wallet/github-bonus
Section titled “GET /api/v1/wallet/github-bonus”Status of the one-time GitHub connection bonus for the authenticated user. Reads local state only and never contacts GitHub. When the offer is disabled the response carries only { "enabled": false }, plus the caller’s own historical claim if any.
This endpoint takes no parameters.
curl -X GET 'https://api.hoody.com/api/v1/wallet/github-bonus' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.getGithubBonus();{ "statusCode": 200, "message": "GitHub bonus status retrieved successfully", "data": { "enabled": true, "repo": "HoodyNetwork/hoody-sdk", "amount_usd": "5.00", "github_linked": true, "github_username": "octocat", "claimed": false, "identity_claimed_elsewhere": false, "claim": null }}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
POST /api/v1/wallet/github-bonus/claim
Section titled “POST /api/v1/wallet/github-bonus/claim”Grant the one-time GitHub connection bonus when eligible. Idempotent: a second call returns result: "already_claimed" and credits nothing. The HTTP status is always 200; the outcome lives in data.result.
curl -X POST 'https://api.hoody.com/api/v1/wallet/github-bonus/claim' \ -H 'Authorization: Bearer <token>'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.wallet.claimGithubBonus();{ "statusCode": 200, "message": "Bonus granted", "data": { "result": "granted", "amount_usd": "5.00", "transaction_id": "507f1f77bcf86cd799439300", "claim": { "amount_usd": "5.00", "at": "2025-01-21T20:30:00.000Z", "transaction_id": "507f1f77bcf86cd799439300" } }}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}{ "statusCode": 429, "error": "Too Many Requests", "message": "Claim rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Ask the resource owner to grant you access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |