Bearer session JWT
Register, verify, or sign in, then manage projects, members, and API keys.
Browse Auth endpoints →Universal Gateway Transaction Platform
One integration for smart accounts, sponsored gas, security analysis, and cross-chain routing—built for teams that want a reliable path from intent to finality.
https://api.ugtp.io/v1Sponsor gas and track execution through one UGTP flow.
→Start with identityCreate a smart accountResolve or create an ERC-4337 account for an owner address.
→Route assetsBuild a cross-chain swapQuote, prepare, sign, submit, and track a LI.FI-backed route.
→Quickstart
Keep secrets server-side, verify your environment, then build the same prepare–sign–submit loop for every operation.
Use a session JWT for onboarding and a project X-API-Key for data-plane requests.
Read the guide →Prepare an unsigned user operation, then sign its userOperationHash client-side.
Read the guide →Submit the signed operation and poll its operation id until terminal status.
Read the guide →curl "https://api.ugtp.io/v1/network/list" \
-H "X-API-Key: $UGTP_API_KEY"Environment
The portal, examples, and precise Swagger targets follow the selected deployment environment.
https://api.ugtp.io/v1Production metadata and examples do not expose staging hosts.
Authentication
Session JWTs administer projects and keys. Project API keys authenticate application traffic; never place either credential in browser code or public AI prompts.
Register, verify, or sign in, then manage projects, members, and API keys.
Browse Auth endpoints →Send the project key on data-plane calls and rotate it without changing your integration flow.
Manage project keys →System architecture
UGTP keeps client signing explicit while coordinating security, sponsorship, routing, and network execution behind one gateway.
Builds intent and signs user-operation hashes.
Authenticates public requests and orchestrates account, swap, fee, and transaction APIs.
Analyzes transaction intent before submission.
Prepares, submits, and tracks ERC-4337 user operations.
Calculates fees and sponsors gasless operations for supported assets.
Returns same-chain swap and cross-chain route execution data.
Executes the submitted operation or routed transfer.
Integration profiles
Use these profiles to place retries, validation, observability, and user messaging at the correct boundary.
External provider
Provide route discovery and execution data for UGTP same-chain swaps and cross-chain swaps.
Swap quote, route preparation, and routed transfer tracking
Routing data crosses from the UGTP gateway to an external routing provider before network execution.
LI.FI operates the external routing provider; UGTP owns the gateway integration and user-facing API contract.
Repository evidence: public/openapi.yaml /crosschain/* Cross-Chain routes; src/content/endpoints.ts Swap group and the deployed swap Swagger tag; LI.FI official documentation.
Official provider documentation ↗UGTP service
Prepare, submit, and track ERC-4337 user operations behind the public Gateway transaction API.
Preparation, submission, and execution tracking
The gateway passes validated operation intent into UGTP execution services.
UGTP operates the Engine boundary exposed through the public transaction and account APIs.
Repository evidence: public/openapi.yaml Account and Transactions sections; src/content/endpoints.ts Accounts and Transactions groups.
UGTP service
Sponsor gasless ERC-4337 operations and calculate fees when the selected asset is supported.
Fee estimation and transaction sponsorship
The execution flow relies on UGTP sponsorship policy before the operation reaches the network.
UGTP operates sponsorship policy and the Paymaster boundary exposed by public transaction responses.
Repository evidence: relevant Transactions definitions in public/openapi.yaml; Fees, Networks, and Transactions groups in src/content/endpoints.ts.
Core concepts
Accounts define identity, user operations carry signed intent, and operation records expose progress through finality.
Resolve deterministic account addresses, create account records, and inspect deployment state.
Prepare an unsigned operation, sign its hash client-side, and submit it before it expires.
Prepare, submit, and poll gasless transaction operations through terminal execution status.
UGTP mirrors Engine lifecycle updates asynchronously; public clients poll transaction status because customer-configurable webhook subscriptions are not currently exposed.
Discover serviceable networks and supported fee tokens before preparing an operation.
Operate
Prepare and sign once, then follow the stable operation identifier to a terminal state.
userOpHash is the stable correlation key for the operation. transactionHash is the current outer transaction hash and can change during replacement or recovery.
If submission times out before a response, it is safe to resend the same signed operation with the same userOpHash. Do not prepare or sign a replacement while that operation remains active; continue polling the original userOpHash.
Prepare the operation, sign the returned hash, and retain its userOpHash as the stable operation identifier.
Submit the signed operation and poll by userOpHash. The transactionHash identifies the current outer handleOps transaction and can change when that transaction is replaced.
Treat confirmed as mined and finalized as reorg-safe. Continue tracking the stable userOpHash if a reorg returns the operation to submitted.
Asynchronous status
Use polling as the public integration contract and tolerate retried synchronization.
| Status | Meaning | Client action |
|---|---|---|
unknown | No operation record was found for this userOpHash. | Verify the userOpHash and network before preparing a replacement operation. |
received | The operation is recorded and waiting to enter the submission queue. | Keep polling by userOpHash; do not create a replacement while it remains active. |
queued | The operation is queued for relayer submission. | Keep polling by userOpHash; do not create a replacement while it remains active. |
submitted | The operation has a current outer transactionHash and is awaiting a mined receipt. | Keep polling by userOpHash because the current transactionHash can change during replacement. |
confirmed | The operation was mined but has not yet reached the network's reorg-safe depth. | Do not retry; continue tracking until finalized if reorg safety matters. |
finalized | The mined operation reached the network's configured reorg-safe confirmation depth. | Do not retry; this is the successful reorg-safe state. |
failed | Execution failed and the operation will not advance. | Inspect the reported error, correct the cause, then prepare and sign a new operation. |
dropped | The operation was dropped and will not advance. | Prepare and sign a new operation if the action is still required. |
{
"userOpHash": "0xabc...",
"transactionHash": "0xdef...",
"status": "confirmed",
"reason": null,
"feeBreakdown": null
}Pricing data
Reserve the estimate before signing, then reconcile the actual fee returned after execution.
Fee estimates are pre-execution planning values. Keep the returned reserve outside the transfer or swap so the submitted operation can pay its gas and applicable UGTP fee.
Account history reports actual collected fee components only after a terminal receipt persists them; the fee can be null before settlement.
For paymaster-backed ERC-20 operations, the UGTP fee is a $0.05 static fee plus 0.1% of the transferred input value. Native self-funded operations do not pay a UGTP fee.
Use the returned fee-token address, symbol, and decimals to identify the asset and interpret all token-denominated amounts.
When present, the signed maximum is the worst-case amount authorized before execution; it is a ceiling, not the settled charge.
After settlement, compare the collected amount with any refunded amount to reconcile what the operation actually paid.
The relayer outer-transaction cost reports the network cost of the outer transaction separately from token-denominated charges.
Read additional Paymaster accounting fields only when present in the response; availability depends on the operation and persisted receipt data.
Onchain reference
Use the Paymaster proxy as the stable integration address on supported mainnets; its backing implementation can be upgraded.
0x1Fc1032DD0A8702fB4b0EE93Fbb746E151DF7625View on block explorer ↗0x1Fc1032DD0A8702fB4b0EE93Fbb746E151DF7625View on block explorer ↗0x1Fc1032DD0A8702fB4b0EE93Fbb746E151DF7625View on block explorer ↗0x1Fc1032DD0A8702fB4b0EE93Fbb746E151DF7625View on block explorer ↗0x1Fc1032DD0A8702fB4b0EE93Fbb746E151DF7625View on block explorer ↗0x1Fc1032DD0A8702fB4b0EE93Fbb746E151DF7625View on block explorer ↗Workflow guide
Treat preparation as an expiring snapshot. Sign only its returned hash, submit it, then poll operation status by userOpHash to reach a terminal state.
Complete reference
All 50 endpoints. Curated endpoints are preserved here with request context and links to the best available Swagger tag or area.
1 endpoint
/healthHealth checkReturns service health. No authentication required.
Authentication: None
{
"status": "ok",
"timestamp": "2026-06-18T12:00:00Z",
"version": "1.0.0"
}6 endpoints
/auth/registerRegisterRegister a new user with name, email, and password (min 8 chars). Emails a verification code (when EMAIL_PROVIDER=console, the gateway logs the code to its console). Returns 400 if the email is from a disposable/throwaway domain ({ "error": "Disposable email addresses are not allowed" }). Returns 429 Too Many Requests if the rate limit is exceeded — this endpoint is strictly limited to prevent email bombing (check the Retry-After response header).
Authentication: None
name string requiredemail string requiredpassword string requiredconfirmPassword string required{
"name": "Jane Dev",
"email": "user@example.com",
"password": "********",
"confirmPassword": "********"
}{
"message": "Verification email sent",
"email": "user@example.com"
}/auth/verifyVerify emailVerify the email with the 10-character code sent during registration. Returns a session JWT used for the project & API-key management endpoints. (The API key itself is minted later — see Projects & API Keys.) Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: None
token string required{
"token": "A1B2C3D4E5"
}{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"message": "Email verified.",
"systemRole": "client_admin"
}/auth/loginLoginAuthenticate with email and password. Returns a session JWT (for the project & API-key management endpoints) plus the caller's platform systemRole (owner | system_admin | client_admin). Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: None
email string requiredpassword string required{
"email": "user@example.com",
"password": "********"
}{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"email": "user@example.com",
"systemRole": "client_admin"
}/auth/resendResend codeResend the email verification code for an unverified account. Requests are rate-limited to one per minute. Returns 429 Too Many Requests if the rate limit is exceeded — this endpoint is strictly limited to prevent email bombing (check the Retry-After response header).
Authentication: None
email string required{
"email": "user@example.com"
}{
"message": "New verification code sent",
"email": "user@example.com"
}/auth/change-passwordChange passwordChange the signed-in user's password. Verifies currentPassword; newPassword must be at least 8 characters and match confirmPassword.
Authentication: Bearer JWT (client session)
currentPassword string requirednewPassword string requiredconfirmPassword string required{
"currentPassword": "********",
"newPassword": "********",
"confirmPassword": "********"
}{
"message": "Password updated."
}/auth/current-userCurrent userReturns the signed-in user with their live platform systemRole (owner | system_admin | client_admin), read from the DB — so a role change is reflected on the next load without re-login.
Authentication: Bearer JWT (client session)
{
"id": "ugtp_user_a1b2c3d4e5f6",
"email": "user@example.com",
"name": "Jane Dev",
"systemRole": "client_admin"
}18 endpoints
/project/createCreate projectCreate a project. The authenticated user becomes its owner (only owner/admin members can mint API keys). Optionally seeds additional members by email and always auto-issues a full-access API key named after the project (raw key in apiKey.value — also persisted, so it stays retrievable later by owners/admins via GET /project/:projectId/api-key). Unknown/duplicate member emails never fail the request — they are reported in warnings instead.
Authentication: Bearer JWT (client session)
name string requiredmembers array{
"name": "My App",
"members": [
{
"email": "teammate@example.com",
"role": "admin"
}
]
}{
"id": "ugtp_proj_a1b2c3d4e5f6",
"name": "My App",
"apiKey": {
"id": "ugtp_project_api_key_a1b2c3d4e5f6",
"name": "My App",
"keyPrefix": "ugtp2_0123",
"value": "ugtp2_0123456789abcdef0123456789abcdef"
},
"warnings": []
}/project/:projectIdDelete project (soft delete)Owner-only soft delete: archives the project (marks it inactive) and revokes all its still-active API keys. Nothing is removed from the database — operations, fees, status events, security reports, and memberships are retained for history/analytics. Idempotent — repeat calls still return 204. Returns 404 both if the project doesn't exist and if the caller is not its owner (non-owners get the same not-found response, never a 403).
Authentication: Bearer JWT (project owner)
projectId string required/project/listList my projectsProjects the caller is a member of. Archived (soft-deleted / inactive) projects are excluded. Each item includes membersCount (all members), apiKeysCount (active keys only), lifiFeePercent (the project's LI.FI integrator fee, as a percent — e.g. 0.2 = 0.2%), and lifiIntegrator (the LI.FI Partner Portal integration id the fees are attributed to).
Authentication: Bearer JWT (client session)
{
"projects": [
{
"id": "ugtp_proj_a1b2c3d4e5f6",
"name": "My App",
"isActive": true,
"role": "owner",
"createdAt": "2026-06-18T12:00:00.000Z",
"membersCount": 3,
"apiKeysCount": 2,
"lifiFeePercent": 0.2,
"lifiIntegrator": "extrasafe"
}
]
}/project/:projectId/feesSet LI.FI integrator feeSet the project's LI.FI integrator fee. lifiFeePercent is a human-facing percent (e.g. 0.25 = 0.25%), 0–2, at most 2 decimal places (it must map exactly onto integer basis points). Requires an owner/admin membership on the project, or platform staff.
Authentication: Bearer JWT (project owner/admin or platform staff)
projectId string requiredlifiFeePercent number required{
"lifiFeePercent": 0.25
}{
"projectId": "ugtp_proj_a1b2c3d4e5f6",
"lifiFeePercent": 0.25
}/project/allList all projects (staff)Platform-staff only (owner / system_admin): every project, sorted by transaction count (desc), capped at 50, with an optional case-insensitive name search. Backs the owner/admin project picker; clients use GET /project/list (scoped to their memberships).
Authentication: Bearer JWT (platform owner/system admin)
search stringlimit number{
"projects": [
{
"id": "ugtp_proj_a1b2c3d4e5f6",
"name": "Acme",
"isActive": true,
"transactionCount": 4210,
"createdAt": "2026-06-18T12:00:00.000Z"
}
]
}/project/:projectId/api-keyList API keysList a project's API keys. Requires membership on the project. Each key includes a value field (the raw key string, or null if it was issued before plaintext storage was added) — but only when the caller is a project owner or admin; viewers get every other field with value omitted entirely.
Authentication: Bearer JWT (project member)
projectId string required{
"apiKeys": [
{
"id": "ugtp_key_a1b2c3d4e5f6",
"name": "Server key",
"keyPrefix": "ugtp2_0123",
"scopes": [
"full_access"
],
"isActive": true,
"expiresAt": null,
"lastUsedAt": "2026-06-18T12:00:00.000Z",
"createdAt": "2026-06-18T12:00:00.000Z",
"revokedAt": null,
"value": "ugtp2_0123456789abcdef0123456789abcdef"
}
]
}/project/:projectId/api-key/createCreate API keyMint a project API key. The raw key is returned in this response and also persisted (alongside its SHA-256 hash, used for auth) so it stays retrievable later by project owners/admins via GET /project/:projectId/api-key. Requires an owner/admin membership on the project. A project can hold at most ONE active key: returns 409 Conflict while an active (non-revoked, unexpired) key exists — revoke it first to mint a replacement.
Authentication: Bearer JWT (project owner/admin)
projectId string requiredname string requiredscopes string[]{
"name": "Server key",
"scopes": [
"full_access"
]
}{
"id": "ugtp_key_a1b2c3d4e5f6",
"apiKey": "ugtp2_0123456789abcdef0123456789abcdef",
"keyPrefix": "ugtp2_0123"
}/project/:projectId/api-key/:keyIdRevoke API keyRevoke a project API key. Requires an owner/admin membership on the project.
Authentication: Bearer JWT (project owner/admin)
projectId string requiredkeyId string required/project/:projectId/members/listList membersList project members. Readable by any project member or platform staff.
Authentication: Bearer JWT (project member or platform staff)
projectId string required{
"members": [
{
"id": "ugtp_member_a1b2c3d4e5f6",
"userId": "ugtp_user_a1b2c3d4e5f6",
"email": "user@example.com",
"name": "Jane Dev",
"role": "owner",
"createdAt": "2026-06-18T12:00:00.000Z"
}
]
}/project/:projectId/members/addAdd or invite memberAdd a project member by email. If the email belongs to an existing UGTP user they're added directly (201, { status: "added", member }). If the email is new, a pending invitation is created and emailed to the recipient (202, { status: "invited", email }) — see /project/invitations/accept. Requires an owner/admin membership on the project. Returns 404 if the project doesn't exist, 400 if the email is already a member.
Authentication: Bearer JWT (project owner/admin)
projectId string requiredemail string requiredrole string{
"email": "teammate@example.com",
"role": "viewer"
}{
"added": {
"status": "added",
"member": {
"userId": "ugtp_user_a1b2c3d4e5f6",
"email": "teammate@example.com",
"name": "Teammate",
"role": "viewer"
}
},
"invited": {
"status": "invited",
"email": "newperson@example.com"
}
}/project/:projectId/invitationsList pending invitationsList a project's pending invitations. Requires an owner/admin membership on the project.
Authentication: Bearer JWT (project owner/admin)
projectId string required{
"invitations": [
{
"id": "ugtp_invite_a1b2c3d4e5f6",
"email": "teammate@example.com",
"role": "viewer",
"status": "pending",
"expiresAt": "2026-07-20T12:00:00.000Z",
"createdAt": "2026-07-13T12:00:00.000Z"
}
]
}/project/:projectId/invitations/:invitationId/resendResend invitationResend the invitation email. The invitation must still be pending and belong to this project (400 otherwise). Requires an owner/admin membership on the project.
Authentication: Bearer JWT (project owner/admin)
projectId string requiredinvitationId string required/project/:projectId/invitations/:invitationId/cancelCancel invitationCancel a pending invitation. The invitation must still be pending and belong to this project (400 otherwise). Requires an owner/admin membership on the project.
Authentication: Bearer JWT (project owner/admin)
projectId string requiredinvitationId string required/project/:projectId/members/:memberIdRemove memberRemove a non-owner project member. Requires an owner/admin membership on the project.
Authentication: Bearer JWT (project owner/admin)
projectId string requiredmemberId string required/project/invitations/acceptPreview invitationPublic, session-less preview of a project invitation for an accept-invitation landing page — shows who invited the recipient and to which project before they set a password. Read-only. Returns 404 if the token is unknown, 410 if it expired, 400 if token is missing.
Authentication: None
token string required{
"projectName": "Acme",
"email": "teammate@example.com",
"role": "viewer",
"expiresAt": "2026-07-20T12:00:00.000Z"
}/project/invitations/acceptAccept invitationPublic, session-less. Consumes the invite token and either creates the account + project membership for a new email (auto-logs in, returning a real sessionToken) or attaches an already-existing user to the project (requiresLogin: true, sessionToken: null — the client must log in normally; auto-login off just the invite token would let anyone with the link take over an existing account). Returns 404 if the token is unknown, 410 if it expired. Rate-limited to 5 requests/hour per IP+email — check the Retry-After response header on 429.
Authentication: None
token string requiredpassword string requiredname string required{
"token": "a1b2c3d4e5f6...",
"password": "********",
"name": "Jane Dev"
}{
"newUser": {
"requiresLogin": false,
"sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"projectId": "ugtp_proj_a1b2c3d4e5f6",
"email": "teammate@example.com"
},
"existingUser": {
"requiresLogin": true,
"sessionToken": null,
"projectId": "ugtp_proj_a1b2c3d4e5f6",
"email": "teammate@example.com"
}
}/api-key/allList manageable API keysAPI keys the caller can manage with their owning project, newest first, capped at 100: every key for platform staff (owner / system_admin), or just the caller's owner/admin projects' keys for a project admin. Backs the cross-project key console.
Authentication: Bearer JWT (platform staff or project owner/admin)
{
"apiKeys": [
{
"id": "ugtp_key_a1b2c3d4e5f6",
"name": "Server key",
"keyPrefix": "ugtp2_0123",
"scopes": [
"full_access"
],
"isActive": true,
"projectId": "ugtp_proj_a1b2c3d4e5f6",
"projectName": "Acme",
"lastUsedAt": "2026-06-18T12:00:00.000Z",
"createdAt": "2026-06-18T12:00:00.000Z",
"revokedAt": null,
"revokedBy": null
},
{
"id": "ugtp_key_f6e5d4c3b2a1",
"name": "Old key",
"keyPrefix": "ugtp2_9876",
"scopes": [
"full_access"
],
"isActive": false,
"projectId": "ugtp_proj_a1b2c3d4e5f6",
"projectName": "Acme",
"lastUsedAt": null,
"createdAt": "2026-06-10T12:00:00.000Z",
"revokedAt": "2026-06-17T09:30:00.000Z",
"revokedBy": {
"name": "Ada Admin",
"email": "ada@acme.com"
}
}
]
}/api-key/:keyId/revokeRevoke an API keyRevoke an API key by id. Platform staff may revoke any key; a project owner/admin may revoke only keys in a project they manage. Backs the cross-project key console.
Authentication: Bearer JWT (platform staff or project owner/admin)
keyId string required3 endpoints
/dashboard/statsDashboard statsDashboard metrics for a day/week/month/custom period across all projects the session user can access, or one project when projectId is provided: operation counts, platform fees grouped by network → fee token (token totals plus per-token USD from the Chainlink price snapshotted on each fee, in micros where 1e6 = $1), and a separate lifi section with the LI.FI integrator fee earned on swap / cross_chain_swap operations (totals, grouped by operation kind, and grouped by network → fee token). Fee USD fields are null when no Chainlink price was snapshotted for that token/operation.
Authentication: Bearer JWT (project member)
projectId stringperiod stringfrom ISO datetimeto ISO datetimeincludeTestnets string{
"period": "week",
"operations": {
"total": 42,
"byStatus": {
"confirmed": 40,
"failed": 2
},
"byNetwork": {
"42161": 42
}
},
"fees": {
"totalCollectedUsdMicros": "1250000",
"totalNetUsdMicros": "900000",
"byNetwork": [
{
"networkId": "42161",
"operations": 42,
"collectedUsdMicros": "1250000",
"netUsdMicros": "900000",
"tokens": [
{
"feeAssetId": "0xB97E...",
"symbol": "USDC",
"decimals": 6,
"gasFeeRaw": "850000",
"staticFeeRaw": "50000",
"transferFeeRaw": "400000",
"collectedFeeRaw": "1250000",
"netRevenueRaw": "1250000",
"operations": 40,
"collectedUsdMicros": "1250000",
"netUsdMicros": "900000"
}
]
}
]
},
"lifi": {
"totalFeeUsdMicros": "300000",
"byKind": {
"swap": {
"operations": 5,
"feeUsdMicros": "200000"
},
"cross_chain_swap": {
"operations": 2,
"feeUsdMicros": "100000"
}
},
"byNetwork": [
{
"networkId": "42161",
"tokens": [
{
"assetId": "0xB97E...",
"symbol": "USDC",
"decimals": 6,
"feeTokenRaw": "300000",
"feeUsdMicros": "300000",
"operations": 7
}
]
}
]
}
}/dashboard/account-seriesAccount statistics (Users) time seriesNew accounts bucketed over a time window (1 account = 1 point on its creation date), split by network, for the Users statistics page. Returns zero-filled continuous buckets plus the pre-window baseline per network, so a cumulative total-growth curve (or per-bucket new accounts) can be rendered client-side. period picks the window; bucket is the independent granularity (derived from period when omitted). Filters narrow which accounts are counted: networkId, address, activeWithin (accounts with an operation in the last window), and projectId (accounts that transacted under that project). Platform staff see all accounts; clients are scoped to accounts that transacted under a project they belong to.
Authentication: Bearer JWT (project member)
period stringbucket stringfrom ISO datetimeto ISO datetimenetworkId stringaddress stringactiveWithin stringprojectId string{
"period": "month",
"from": "2026-06-07T00:00:00.000Z",
"to": "2026-07-07T00:00:00.000Z",
"bucket": "day",
"networks": [
{
"networkId": "137",
"name": "Polygon PoS"
},
{
"networkId": "42161",
"name": "Arbitrum One"
}
],
"baseline": {
"total": 84,
"byNetwork": {
"137": 60,
"42161": 24
}
},
"series": [
{
"bucket": "2026-06-07T00:00:00.000Z",
"total": 4,
"byNetwork": {
"137": 3,
"42161": 1
}
},
{
"bucket": "2026-06-08T00:00:00.000Z",
"total": 0,
"byNetwork": {
"137": 0,
"42161": 0
}
}
],
"total": 44
}/dashboard/transactionsDashboard transactionsPaginated transaction list across all projects the session user can access, or one project when projectId is provided, with status, time, network, transaction-hash, and user-operation-hash filters. Each row includes its prepare-time security verdict (safe | unsafe | unavailable) when one was recorded. Each row's fee object also carries collectedUsdMicros (gross fee — the collected amount valued in USD micros at the row's snapshotted Chainlink price), netProfitUsdMicros (paymaster net margin: collected fee minus relayer gas, both at execution-time prices, USD micros), netProfitFeeRaw (the same net margin expressed in the fee token's base units — the token-denominated profit, not the gross; nullable, may be negative) and the LI.FI integrator fee fields (lifiFeeAssetId/Symbol/Decimals, lifiFeeTokenRaw, lifiFeeUsdMicros) — all nullable, populated only when a price/receipt was available (LI.FI fields additionally only for swap / cross_chain_swap operations with a terminal receipt).
Authentication: Bearer JWT (project member)
projectId stringlimit numberoffset numberstatus stringnetworkId stringtransactionHash stringuserOperationHash stringfrom ISO datetimeto ISO datetimeincludeTestnets string{
"transactions": [
{
"id": "ugtp_op_a1b2c3d4e5f6",
"operationKind": "transfer",
"status": "confirmed",
"networkId": "42161",
"transactionHash": "0xdef...",
"userOperationHash": "0xabc...",
"fee": {
"symbol": "USDC",
"collectedFeeRaw": "25000",
"collectedUsdMicros": "25000",
"netProfitUsdMicros": "18000",
"netProfitFeeRaw": "18000",
"lifiFeeAssetId": null,
"lifiFeeAssetSymbol": null,
"lifiFeeAssetDecimals": null,
"lifiFeeTokenRaw": null,
"lifiFeeUsdMicros": null
},
"security": {
"verdict": "safe"
},
"createdAt": "2026-06-18T12:00:00.000Z"
},
{
"id": "ugtp_op_b2c3d4e5f6a1",
"operationKind": "swap",
"status": "confirmed",
"networkId": "137",
"transactionHash": "0xfed...",
"userOperationHash": "0xcba...",
"fee": {
"symbol": "USDC",
"collectedFeeRaw": "60000",
"collectedUsdMicros": "60000",
"netProfitUsdMicros": "45000",
"netProfitFeeRaw": "45000",
"lifiFeeAssetId": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
"lifiFeeAssetSymbol": "USDT",
"lifiFeeAssetDecimals": 6,
"lifiFeeTokenRaw": "1000000",
"lifiFeeUsdMicros": "1000000"
},
"security": {
"verdict": "safe"
},
"createdAt": "2026-06-18T12:05:00.000Z"
}
],
"total": 2,
"limit": 25,
"offset": 0
}6 endpoints
/account/createResolve account (derive + cache)Derive the deterministic smart-account address for an owner on a network (via the engine) and cache it. Idempotent — re-derivation refreshes the cached details and keeps a stable id. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
ownerAddress string requirednetworkId string required{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"networkId": "43114"
}{
"id": "ugtp_acc_a1b2c3d4e5f6",
"address": "0x1234567890abcdef1234567890abcdef12345678",
"networkId": "43114",
"networkKind": "evm",
"details": {
"schemaVersion": 1,
"networkKind": "evm",
"evm": {
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"implementationVersion": "v3.3"
}
},
"createdAt": "2026-06-18T12:00:00.000Z",
"updatedAt": "2026-06-18T12:00:00.000Z"
}/account/resolve-singleSingle network-independent resolveMap one owner EOA to its deterministic smart-account address. The address is network-independent (identical on every chain) — no networkId needed. Stateless (creates no account row). For many owners prefer /account/resolve-batch. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
ownerAddress string required{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0"
}{
"address": "0x1234567890abcdef1234567890abcdef12345678"
}/account/infoDerive address (preview)Stateless preview of the deterministic smart-account address (+ implementation version + on-chain deployment flag) for an owner — without persisting an account. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
ownerAddress string requirednetworkId string required{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"networkId": "43114"
}{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"address": "0x1234567890abcdef1234567890abcdef12345678",
"networkId": "43114",
"isDeployed": false,
"kernelVersion": "v3.3"
}/account/is-deployedCheck deploymentWhether a smart-account address is already deployed on-chain for the given network. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
address string requirednetworkId string required{
"isDeployed": true
}/account/seriesAccount-creation series (admin chart)Account-creation time series for the admin dashboard's Accounts chart: zero-filled per-bucket NEW account counts (UTC-aligned buckets) plus a pre-window baseline per network so the client can derive a cumulative curve (cumulative = baseline + running sum). networks is ordered by in-window count, descending. Omitting bucket picks a granularity from the window length (≤31d day, ≤~6mo week, else month). Platform staff see all accounts; clients are scoped to accounts attributed (via operations) to their projects.
Authentication: Bearer JWT
period string requiredbucket stringfrom stringto stringnetworkId stringaddress stringactiveWithin stringprojectId stringincludeTestnets string{
"period": "month",
"from": "2026-06-10T00:00:00.000Z",
"to": "2026-07-10T00:00:00.000Z",
"bucket": "day",
"networks": [
{
"networkId": "137",
"name": "Polygon PoS"
},
{
"networkId": "42161",
"name": "Arbitrum One"
}
],
"baseline": {
"total": 7,
"byNetwork": {
"137": 5,
"42161": 2
}
},
"series": [
{
"bucket": "2026-06-10T00:00:00.000Z",
"total": 0,
"byNetwork": {}
},
{
"bucket": "2026-06-11T00:00:00.000Z",
"total": 3,
"byNetwork": {
"137": 2,
"42161": 1
}
}
],
"total": 3
}/account/resolve-batchBatch-resolve ownersMap many owner EOAs to their smart-account addresses in one call. The address is network-independent, so only owner addresses are needed. Stateless (creates no accounts). Default cap: 1,000 owners per request (env-configurable via RESOLVE_BATCH_MAX_ADDRESSES) — paginate for larger sets. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
ownerAddresses string[] required{
"ownerAddresses": [
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0"
]
}{
"results": [
{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"smartAccountAddress": "0x1234567890abcdef1234567890abcdef12345678"
}
],
"count": 1
}5 endpoints
/transaction/preparePrepare (generate user operation)Build an unsigned ERC-4337 user operation for the given calls. Runs the security check (an unsafe verdict returns 422). transferredAssets are the asset(s) the gasless fee is charged against. The response includes ugtpFee — the worst-case fee the paymaster will charge ({ tokenAmount, feeToken }, base units). Sign the returned userOperationHash client-side, then call /transaction/submit. The prepared operation is held server-side for a limited time (default 30 minutes). If it expires before submit, prepare again. Returns 409 if a duplicate user operation (same UserOp hash) was already materialized. If the simulated calldata reverts deterministically (e.g. the route's bridge/DEX rejects the amount as below its minimum), returns 422 with a coded error ({ error, code, reason }) — e.g. code SWAP_AMOUNT_TOO_SMALL, or EXECUTION_SIMULATION_REVERTED with the raw revert reason. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
accountId string requirednetworkId string requiredcalls Call[] requiredtransferredAssets Asset[] requiredfeeToken string{
"accountId": "ugtp_acc_a1b2c3d4e5f6",
"networkId": "43114",
"calls": [
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"value": "0x2386f26fc10000",
"data": "0x"
}
],
"transferredAssets": [
{
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"amount": "0x2386f26fc10000"
}
]
}{
"operationId": "ugtp_op_a1b2c3d4e5f6",
"userOperation": {
"sender": "0x1234567890abcdef1234567890abcdef12345678",
"nonce": "0x0",
"initCode": "0x",
"callData": "0x...",
"accountGasLimits": "0x...",
"preVerificationGas": "0x...",
"gasFees": "0x...",
"paymasterAndData": "0x...",
"signature": "0x"
},
"userOperationHash": "0xabc...",
"security": {
"verdict": "safe",
"reason": null,
"provider": "mock"
},
"ugtpFee": {
"tokenAmount": "52000",
"feeToken": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f"
}
}/transaction/submitSubmit (send signed user operation)Submit the client-signed user operation to the engine relayer. Returns the engine UserOpStatus. Returns 404 if the operation is not found or has expired — prepare it again. Returns 409 if this user operation was already submitted under a different operation id, or the operation was already submitted (status mismatch). Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
operationId string requiredsignature string required{
"operationId": "ugtp_op_a1b2c3d4e5f6",
"signature": "0x..."
}{
"operationId": "ugtp_op_a1b2c3d4e5f6",
"status": "queued",
"userOperationHash": "0xabc...",
"networkId": "43114"
}/transaction/:idGet operation statusLive engine status of an operation (re-polls the engine). status is the engine UserOpStatus: unknown | received | queued | submitted | confirmed | finalized | failed | dropped. finalized = execution tx reached the network's reorg-safe confirmation depth; terminal. Operations normally appear from submit onward, and a prepared-but-never-submitted operation normally returns 404. An operation may occasionally be visible with status received before submit; clients must not treat visibility as proof of submission and should continue the documented sign-and-submit flow. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
id string required{
"operationId": "ugtp_op_a1b2c3d4e5f6",
"status": "confirmed",
"transactionHash": "0xdef...",
"userOperationHash": "0xabc...",
"networkId": "43114",
"replacementCount": 1,
"reason": null
}/transactionList operationsList the calling project's operations, newest first, with optional account/status filters and paging. status is the last-known mirrored engine status (unknown | received | queued | submitted | confirmed | finalized | failed | dropped); call /transaction/:id for a live read. Operations normally appear after submit. An operation may occasionally be listed with status received before submit; clients must not treat listing presence as proof of submission and should continue the documented sign-and-submit flow. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
accountId stringstatus stringlimit numberoffset number{
"operations": [
{
"operationId": "ugtp_op_a1b2c3d4e5f6",
"operationKind": "transfer",
"status": "confirmed",
"networkId": "43114",
"transactionHash": "0xdef...",
"userOperationHash": "0xabc...",
"createdAt": "2026-06-18T12:00:00.000Z"
}
],
"count": 1,
"limit": 50,
"offset": 0
}/transaction/transferPrepare same-chain transferConvenience flow for same-chain transfers: encodes one or more transfer legs into a single user operation (multi-token supported). Like /prepare it returns an unsigned user op to sign + submit (plus ugtpFee — the worst-case paymaster fee in the fee token); an unsafe security verdict returns 422. Cross-chain is not yet available. The prepared operation is held server-side for a limited time (default 30 minutes). If it expires before submit, prepare again. Returns 409 if a duplicate user operation (same UserOp hash) was already materialized. If the simulated calldata reverts deterministically (e.g. the route's bridge/DEX rejects the amount as below its minimum), returns 422 with a coded error ({ error, code, reason }) — e.g. code SWAP_AMOUNT_TOO_SMALL, or EXECUTION_SIMULATION_REVERTED with the raw revert reason. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
ownerAddress string requirednetworkId string requiredtransfers Transfer[] requiredfeeTokenAddress string{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"networkId": "43114",
"transfers": [
{
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"amount": "10000000000000000",
"recipientAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0"
}
]
}{
"operationId": "ugtp_op_a1b2c3d4e5f6",
"userOperation": {
"sender": "0x1234567890abcdef1234567890abcdef12345678",
"nonce": "0x0",
"initCode": "0x",
"callData": "0x...",
"accountGasLimits": "0x...",
"preVerificationGas": "0x...",
"gasFees": "0x...",
"paymasterAndData": "0x...",
"signature": "0x"
},
"userOperationHash": "0xabc...",
"security": {
"verdict": "safe",
"reason": null,
"provider": "mock"
},
"ugtpFee": {
"tokenAmount": "52000",
"feeToken": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f"
}
}4 endpoints
/swap/chainsList swap-supported chainsLI.FI-supported chains filtered to the gateway's serviceable networks. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
{
"chains": [
{
"networkId": "42161",
"name": "Arbitrum One",
"nativeCurrency": "ETH",
"logoUrl": "https://..."
}
]
}/swap/tokens?networkId=List swap tokens for a chainLI.FI tokens available on the given network. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
networkId string required{
"networkId": "42161",
"tokens": [
{
"address": "0x...",
"symbol": "USDC",
"name": "USD Coin",
"decimals": 6,
"networkId": "42161"
}
]
}/swap/quotePreview a same- or cross-chain swapRecommended LI.FI route output + fees for fromToken -> toToken. Set toNetworkId to a different chain for a cross-chain swap. Preview only; no operation is created. feeReserveTokenAmount is the engine's own fee estimate for this exact swap — keep this much of the input token OUTSIDE the swap amount or the op is rejected (ERC-20 input: the paymaster fee; native input: the self-funded native gas; null when the engine estimate is unavailable). ugtpFeeUsd is null for native input (no paymaster involved, no UGTP fee). If the quote-time simulation of the real approve+swap calldata reverts deterministically (e.g. the route's bridge rejects the amount as below its minimum), returns 422 with a coded error ({ error, code, reason }, e.g. code SWAP_AMOUNT_TOO_SMALL) so clients can warn before the user signs. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
ownerAddress string requirednetworkId string requiredtoNetworkId stringfromToken string requiredtoToken string requiredamount string requiredslippage number{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"networkId": "137",
"toNetworkId": "42161",
"fromToken": "0x...",
"toToken": "0x...",
"amount": "1000000",
"slippage": 0.005
}{
"fromAmount": "1000000",
"toAmount": "990000",
"fromAmountUsd": "1.00",
"toAmountUsd": "0.99",
"rate": "0.99",
"minimumReceived": "0.985050",
"minimumReceivedUsd": "0.985",
"networkFeeUsd": "0.01",
"lifiFeesUsd": "0.002",
"ugtpFeeUsd": "0.051",
"ugtpFeeStaticUsd": 0.05,
"ugtpFeePercent": 0.1,
"feeTokenAmount": "0.061",
"feeTokenSymbol": "USDC",
"feeReserveTokenAmount": "0.061",
"slippage": 0.005,
"estimatedTimeSeconds": 30,
"bridge": "uniswap",
"provider": "uniswap"
}/swap/prepareBuild a gasless same- or cross-chain swap user operationWraps the LI.FI swap/bridge tx as a gasless UserOp (approve + swap) on the source networkId, charging the fee from fromToken (or feeToken). For cross-chain (toNetworkId differs) the gasless op runs on the source chain and LI.FI bridges to the destination. The response includes ugtpFee — the worst-case paymaster fee ({ tokenAmount, feeToken }, base units). Sign userOperationHash and submit via /transaction/submit; poll /transaction/:id. An unsafe security verdict returns 422. The prepared operation is held server-side for a limited time (default 30 minutes). If it expires before submit, prepare again. Returns 409 if a duplicate user operation (same UserOp hash) was already materialized. If the simulated calldata reverts deterministically (e.g. the route's bridge/DEX rejects the amount as below its minimum), returns 422 with a coded error ({ error, code, reason }) — e.g. code SWAP_AMOUNT_TOO_SMALL, or EXECUTION_SIMULATION_REVERTED with the raw revert reason. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
ownerAddress string requirednetworkId string requiredtoNetworkId stringfromToken string requiredtoToken string requiredamount string requiredslippage numberfeeToken string{
"ownerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"networkId": "137",
"toNetworkId": "42161",
"fromToken": "0x...",
"toToken": "0x...",
"amount": "1000000",
"slippage": 0.005
}{
"operationId": "ugtp_operation_...",
"userOperation": {
"sender": "0x1234567890abcdef1234567890abcdef12345678",
"nonce": "0x0",
"initCode": "0x",
"callData": "0x...",
"accountGasLimits": "0x...",
"preVerificationGas": "0x...",
"gasFees": "0x...",
"paymasterAndData": "0x...",
"signature": "0x"
},
"userOperationHash": "0xabc...",
"security": {
"verdict": "safe",
"reason": null,
"provider": "mock"
},
"ugtpFee": {
"tokenAmount": "52000",
"feeToken": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f"
}
}3 endpoints
/network/listList networksSupported networks (proxied from the engine catalog). Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
{
"networks": [
{
"name": "Avalanche C-Chain",
"networkId": "43114",
"explorerUrl": "https://snowtrace.io",
"nativeCoin": "AVAX",
"wrappedNative": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"
}
]
}/network/:networkIdGet networkA single network's metadata. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
networkId string required{
"name": "Avalanche C-Chain",
"networkId": "43114",
"explorerUrl": "https://snowtrace.io",
"nativeCoin": "AVAX",
"wrappedNative": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"
}/network/:networkId/tokensList network tokensTokens supported on a network (e.g. fee tokens). Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
networkId string required{
"networkId": "43114",
"tokens": [
{
"address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"symbol": "USDC",
"decimals": 6
}
]
}1 endpoint
/fee/estimateEstimate gasless feePreview the gasless fee (in the fee token) the paymaster would bill for the given calls + transferred assets, without submitting. Pass senderAddress (the smart-account address) directly; omit feeToken for the native-gas estimate. Returns 429 Too Many Requests if the rate limit is exceeded (check the Retry-After response header).
Authentication: X-API-Key
networkId string requiredsenderAddress string requiredcalls Call[] requiredtransferredAssets Asset[] requiredfeeToken string{
"networkId": "43114",
"senderAddress": "0x1234567890abcdef1234567890abcdef12345678",
"calls": [
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
"value": "0x2386f26fc10000",
"data": "0x"
}
],
"transferredAssets": [
{
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"amount": "0x2386f26fc10000"
}
],
"feeToken": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"
}{
"estimatedFee": "0.0512",
"estimatedFeeRaw": "0xc7f8",
"symbol": "USDC"
}3 endpoints
/user/system-admin/createCreate system adminCreate a new system_admin account (name, email, password). Restricted to the platform owner. The account is created pre-verified so the admin can sign in immediately.
Authentication: Bearer JWT (platform owner)
name string requiredemail string requiredpassword string required{
"name": "Ops Admin",
"email": "admin@example.com",
"password": "********"
}{
"id": "ugtp_user_a1b2c3d4e5f6",
"email": "admin@example.com"
}/user/system-admin/listList system adminsList platform staff — owners and system admins. Restricted to the platform owner.
Authentication: Bearer JWT (platform owner)
{
"admins": [
{
"id": "ugtp_user_a1b2c3d4e5f6",
"email": "admin@example.com",
"name": "Ops Admin",
"systemRole": "system_admin",
"createdAt": "2026-06-18T12:00:00.000Z"
}
]
}/user/system-admin/:userId/deleteRemove system adminRevoke a system admin's platform access by demoting them to a client admin (the user account is kept — other records reference it). Restricted to the platform owner; the owner cannot remove their own access, and only system_admin users can be removed.
Authentication: Bearer JWT (platform owner)
(no content)Troubleshooting
Branch on status and stable error code, preserve the operation id in logs, and retry only when the response tells you the request is safe to repeat.
400Correct malformed fields or an unsupported network or token.
401 / 403Refresh the session JWT or verify project API-key scope.
409Reuse the existing operation id and continue polling.
422Inspect the coded verdict, adjust the calls, and prepare again.
429Honor Retry-After and retry with bounded exponential backoff.