Quickstart

Zero to your first 201 Created submission.

0. What you need

Two environments, one wire. The sandbox at https://api.staging.gofundnode.com is live, with open signup and its own database; production runs at https://api.gofundnode.com. The wire is byte-identical — the only things that change between environments are the base URL and the secrets. Start in the sandbox, then promote by swapping those. See Onboarding §3.

1. Install the SDK

npm i @gofundnode/vendor-client
# (shipped inside the gofundnode monorepo today; depend on it by path until published)

2. Submit (SDK)

The SDK owns HMAC signing, timestamping, retries, idempotency, and typed errors so you don't have to.

import { GoFundNodeClient } from "@gofundnode/vendor-client";

const client = new GoFundNodeClient({
  baseUrl:     process.env.GFN_API_BASE_URL!,    // sandbox or production base URL
  tenantApiId: process.env.GFN_TENANT_API_ID!,   // sent as X-GFN-Tenant
  hmacSecret:  process.env.GFN_HMAC_SECRET!,     // signs outbound requests
});

const sub = await client.submitAtsApplication({
  idempotencyKey: `quickstart:${crypto.randomUUID()}`, // tenant-unique, stable per logical job
  tier:           "standard",                           // optional (default "standard")
  payload: {
    applicationUrl:   "https://job-boards.greenhouse.io/example/jobs/12345",
    atsType:          "greenhouse",
    applicantProfile: { fullName: "Ada Lovelace", email: "ada@example.com" },
  },
});

console.log(sub.submissionId, sub.status);
// { submissionId, status, quote: { estimated, max, surge }, balance: { after, held } }
// quote.max is the credit hold; the unused remainder is refunded at settlement.

2b. Submit (raw HMAC, no SDK)

If you can't use the SDK, sign <timestamp>.<raw_body> with HMAC-SHA256. The body must be signed byte-for-byte as transmitted.

TS=$(date +%s)
BODY='{"jobType":"ats.application","tier":"standard","idempotencyKey":"quickstart-001","payload":{"applicationUrl":"https://job-boards.greenhouse.io/example/jobs/12345","atsType":"greenhouse","applicantProfile":{}}}'
SIG=$(printf '%s' "${TS}.${BODY}" | openssl dgst -sha256 -hmac "$GFN_HMAC_SECRET" -r | cut -d' ' -f1)

curl -sS -X POST "$GFN_API_BASE_URL/v1/submissions" \
  -H "X-GFN-Tenant: $GFN_TENANT_API_ID" \
  -H "X-GFN-Timestamp: $TS" \
  -H "X-GFN-Signature: $SIG" \
  -H "Content-Type: application/json" \
  --data-binary "$BODY"

Full signing rules: Auth & HMAC signing.

3. Watch it settle

Two ways to learn the outcome. Prefer webhooks; poll only as a fallback.

import { TERMINAL_STATUSES } from "@gofundnode/vendor-client";

let detail = await client.getSubmission(sub.submissionId);
while (!TERMINAL_STATUSES.has(detail.status)) {
  await new Promise((r) => setTimeout(r, 3_000));
  detail = await client.getSubmission(sub.submissionId);
}
console.log(detail.status, detail.actualCredits);

4. Run the bundled examples

# submit + poll one application
GFN_API_BASE_URL=… GFN_TENANT_API_ID=… GFN_HMAC_SECRET=… \
  npx tsx examples/submit.ts

# idempotent re-submit + 409 conflict handling
npx tsx examples/idempotency-retry.ts

# read-only account snapshot (rate card + balance [+ submission])
GFN_SUBMISSION_ID=… npx tsx examples/account-snapshot.ts

# webhook receiver (separate terminal)
GFN_WEBHOOK_SECRET=… npx tsx examples/webhook-handler.ts
← Portal home Auth & HMAC signing →