API quickstart
Connect a business and upload your first account and transaction from your server.
This guide takes you from partner credentials to a saved transaction. You will make three requests: connect a user and business, create an account, and upload a transaction. No browser session is required.
Before you begin
You need:
- A partner ID, signing secret, and backend URL supplied by Jupid for your staging environment. Request access at slava@jupid.com.
- A user and business you are authorized to synchronize. Use stable IDs from your system; Jupid uses them to recognize repeat requests.
- Node.js, curl, and jq for the examples below.
The backend URL is different from the app URL used for embedding. Confirm that the API is enabled in your environment. Run these examples on your server or development machine; keep the signing secret out of browser and mobile code.
1. Create a signed token
Set the values Jupid supplied. The URL below is a placeholder:
export JUPID_BACKEND_URL="https://your-staging-backend.example.com"
export JUPID_PARTNER_ID="your-partner-id"
export JUPID_EMBED_SECRET="your-staging-signing-secret"Save the following as sign-jupid-token.mjs. Replace the sample user and
business with your staging identities. In your integration, obtain these
values from your trusted server records. Include the person's complete list
of authorized businesses on every call: omitted businesses lose access. Keep
sub stable when switching business_id. This example has one business.
import { createHmac, randomUUID } from "node:crypto"
const now = Math.floor(Date.now() / 1000)
const claims = {
iss: process.env.JUPID_PARTNER_ID,
aud: "jupid-embed",
sub: "user-123",
email: "user@example.com",
name: "Jane Founder",
payload: {
business_id: "business-123",
businesses: [
{ id: "business-123", name: "Acme Studio", role: "owner" },
],
tier: "free",
},
iat: now,
exp: now + 300,
jti: randomUUID(),
}
const unsigned = [{ alg: "HS256", typ: "JWT" }, claims]
.map((value) => Buffer.from(JSON.stringify(value)).toString("base64url"))
.join(".")
const signature = createHmac("sha256", process.env.JUPID_EMBED_SECRET)
.update(unsigned)
.digest("base64url")
console.log(`${unsigned}.${signature}`)Create the token:
export JUPID_TOKEN="$(node sign-jupid-token.mjs)"The token expires after five minutes. Run the command again when you need a fresh token. It uses the same claims and signing rules as Jupid Embed. Use the user's actual business role and your agreed tier; see business access and tier rules.
2. Connect the user and business
curl --fail-with-body --silent --show-error \
--request POST "$JUPID_BACKEND_URL/api/v1/auth/partner" \
--header "X-Jupid-Partner: $JUPID_PARTNER_ID" \
--header "Authorization: Bearer $JUPID_TOKEN" \
--output connection.json
cat connection.jsonExpect HTTP 200 with the mapped Jupid user, selected business IDs, and the authorized business roster:
{
"user_id": "10000000-0000-4000-8000-000000000001",
"organization_id": "10000000-0000-4000-8000-000000000002",
"source_id": "10000000-0000-4000-8000-000000000003",
"organizations": [
{
"business_id": "business-123",
"organization_id": "10000000-0000-4000-8000-000000000002",
"source_id": "10000000-0000-4000-8000-000000000003",
"role": "owner"
}
]
}Save the returned IDs for the next requests:
export JUPID_ORGANIZATION_ID="$(jq -er .organization_id connection.json)"
export JUPID_SOURCE_ID="$(jq -er .source_id connection.json)"
export JUPID_BUSINESS_URL="$JUPID_BACKEND_URL/api/v1/organizations/$JUPID_ORGANIZATION_ID"organization_id identifies the business in Jupid. source_id identifies
your API connection in that business. Repeating this request with the same
partner, user, and business returns the same IDs.
3. Upload an account
jq -n --arg source "$JUPID_SOURCE_ID" '{
source_id: $source,
accounts: [{
external_id: "checking-123",
name: "Operating Checking",
type: "depository",
currency: "USD",
current_balance: 12000.34
}]
}' > accounts.json
curl --fail-with-body --silent --show-error \
--request POST "$JUPID_BUSINESS_URL/accounts" \
--header "X-Jupid-Partner: $JUPID_PARTNER_ID" \
--header "Authorization: Bearer $JUPID_TOKEN" \
--header "Content-Type: application/json" \
--data-binary @accounts.json \
--output account-response.json
cat account-response.jsonExpect HTTP 200 with an accounts array containing id and external_id.
Use the returned Jupid account ID, not checking-123, in the next URL:
export JUPID_ACCOUNT_ID="$(jq -er '.accounts[] | select(.external_id == "checking-123") | .id' account-response.json)"4. Upload a transaction
curl --fail-with-body --silent --show-error \
--request POST "$JUPID_BUSINESS_URL/accounts/$JUPID_ACCOUNT_ID/transactions" \
--header "X-Jupid-Partner: $JUPID_PARTNER_ID" \
--header "Authorization: Bearer $JUPID_TOKEN" \
--header "Content-Type: application/json" \
--data '{"transactions":[{"external_id":"bank-tx-456","amount":-42.50,"date":"2026-09-08","description":"Office supplies"}]}'Expect HTTP 200 with a transactions array containing id and external_id.
The amount is −$42.50: an outgoing payment, expressed in dollars. Incoming
amounts are positive. The date uses YYYY-MM-DD.
A successful response confirms that Jupid saved the transaction and accepted its background-processing event. Categorization and report updates happen afterward, subject to the business's processing entitlement.
5. Verify a repeat
Repeat the transaction request unchanged. It should return the same Jupid
transaction ID. Change the amount or description while keeping external_id
to update that transaction. Jupid preserves local comments and categorization
state when you update bank fields.
If a request fails, inspect the JSON error before continuing:
- 401: generate a fresh token; check the partner ID, secret, and environment.
- 403: connect the user first and use the business signed into the token.
- 422: check the JSON against the request schemas.
- 500 or a lost response: retry the same payload with backoff. A failed response does not necessarily mean that no rows were saved.
See the full error reference for other responses.
Next steps
- Import your initial history in batches of up to 500 records and 1 MiB.
- Read data or reports using the same business URL and authorization headers.
- Embed Jupid so users can work with the data you have synchronized.