Developer Documentation

StridesAway API — Automated UGC

The StridesAway API lets licensed businesses run the full brand-side UGC workflow programmatically: publish briefs, discover creators, invite and select talent, review drafts, and confirm — without touching the web app.

Plans (yearly) — live catalog at GET /api/plans

TierPriceIncludes
Standard$170/yrFull API access (/api/v1/*) · Prepaid wallet (per-currency, bachs converts at top-up) · Reduced 5% fee (max $10) · $20 wallet credit
features: full_api_access, prepaid_wallet, reduced_service_fee, wallet_credit
Pro$250/yrEverything in Standard · Whitelabeling (coming soon) · AI video generation (coming soon) · No service fee (0%)
features: full_api_access, prepaid_wallet, whitelabel, ai_video_generation, no_service_fee
REST + JSONX-API-Key authPrepaid walletAnnual licenseUUID resources
Getting started

Base URL

All endpoints live under /api/v1. Sandbox/staging URLs are provided at onboarding. Every request must set:

HeaderValue
X-API-Keysa_ + 64 hex chars (issued at activation)
Content-Typeapplication/json
Acceptapplication/json

Example — curl

bash
curl -s https://api.stridesaway.com/api/v1/creators \
  -H "X-API-Key: sa_<your_key>"

Authentication

API requests are authenticated with your license key in the X-API-Key header (no Bearer prefix). Keys are issued once when your license activates and are shown only a single time — store them in a secrets manager.

StatusMeaning
200Authenticated & authorized
401Missing, invalid, revoked, or expired key
403Key is valid but the account is banned

Your key is tied to one brand account. All resources created/read with the key belong to that account and are isolated from other customers.

Reference

Conventions

Money

All amounts are decimal major units (dollars, not cents). Examples: 100.00, 49.5. Internally they are integer cents.

Dates & times

ISO 8601 with timezone offset, e.g. 2026-12-01T18:00:00.000Z.

IDs

All resource IDs are UUIDs.

Errors

Errors return an application/json body with a single field:

json
{ "error": "a human-readable message" }
HTTPWhen
400Invalid input / validation failed
401Bad or missing API key
403Insufficient permission / banned account
404Resource not found
409Conflict (wrong state, e.g. already reviewed)
500Internal error (retry; report if persistent)

Pagination

List endpoints accept page (1-based) and per_page. The creators endpoint returns { "items": [...], "total": N, "page": P, "per_page": N }.

Workflow at a glance

  1. 1

    Top up your wallet POST /wallet/top-up → hosted checkout → poll status

  2. 2

    Create a brief POST /briefs

  3. 3

    Fund the brief (wallet) POST /briefs/:id/checkout → instant

  4. 4

    Creators apply GET /briefs/:id/applicants

  5. 5

    Invite or select creators POST /briefs/:id/invite | /select

  6. 6

    Creators submit GET /briefs/:id/submissions

  7. 7

    Review drafts POST /submissions/:id/review

  8. 8

    Confirm & pay POST /submissions/:id/confirm

Payments

Prepaid wallet

Your API key is linked to a brand account with a prepaid wallet. Top it up via a hosted checkout, then funding briefs is an instant server-side debit. The balance is shared with the web dashboard.

GET/wallet· Prepaid balances (all currencies)

All prepaid balances, one per currency. Currency conversion is handled by the payment provider at top-up; briefs are funded from their own-currency wallet.

Response 200

json
[
  { "id": "w1a2...", "brand_id": "b0f0...", "balance": 5000.0, "currency": "USD" },
  { "id": "w3b4...", "brand_id": "b0f0...", "balance": 250000.0, "currency": "NGN" }
]
POST/wallet/top-up· Start a top-up

Start a top-up in a currency. Returns a hosted checkout URL (or completed: true when paid). Omit currency to use the platform currency ( USD).

Body

json
{ "amount": 500.0, "currency": "NGN", "return_url": "https://yourservice.com/wallet/return", "cancel_url": "https://yourservice.com/wallet/cancel" }

Response 200

json
{ "completed": false, "currency": "NGN", "checkout_url": "https://pay.bachs.io/cs_..." }
GET/wallet/top-up/:id/status· Poll / verify a top-up

Poll the top-up. Once payment settles, the balance is credited and completed becomes true with the new balance_after (and the currency). This is also driven by webhooks, so polling is a fallback.

json
{ "status": "completed", "payment_status": "paid", "completed": true, "currency": "NGN", "balance_after": 250500.0 }
GET/wallet/transactions· Wallet ledger

Recent ledger entries (top-ups, brief-funding debits, refund credits), newest first.

Directory

Creators

GET/creators· Creator / clipper directory

Query params

ParamTypeDescription
qstringFree-text search
nichestringFilter by niche (e.g. health, tech)
typestringcreator or clipper
countrystringISO country code
pageintDefault 1
per_pageintDefault 20

Response 200

json
{
  "items": [
    {
      "id": "3f0f...",
      "display_name": "Maya Wellness",
      "bio": "Fitness & lifestyle UGC",
      "avatar_url": "https://...",
      "country": "NG",
      "state": "Lagos",
      "niches": ["health", "wellness", "lifestyle"],
      "types": ["creator"],
      "social_links": { "instagram": "https://instagram.com/..." },
      "follower_counts": { "instagram": 10000 },
      "portfolio_links": ["https://..."],
      "rate": 1500.0,
      "rate_min": null,
      "rate_max": null,
      "currency": "USD"
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 20
}
  • rate / rate_min / rate_max are per-project indicative rates in decimal units.
  • Only non-banned, active creators appear.
Campaigns

Briefs

A brief is a package of deliverables (e.g. “10 product videos”). The total budget is the sum of all deliverable amounts. Two pricing models exist:

  • fixed — creators are paid a set amount per deliverable.
  • cpm — clippers are paid per 1,000 verified views; you set an explicit total_budget pool instead of per-deliverable amounts.
POST/briefs· Create a brief package

Create a brief. It is created in draft status.

Body

json
{
  "title": "Summer Fitness Campaign",
  "description": "UGC videos for our activewear line",
  "currency": "USD",
  "deadline": "2026-12-31T23:59:59Z",
  "required_niche": "health",
  "selection_mode": "brand_selects",
  "pricing_model": "fixed",
  "requires_brand_approval": true,
  "requires_shipping": false,
  "deliverables": [
    {
      "title": "Gym lookbook video",
      "description": "60s vertical video",
      "amount": 100.00,
      "due_date": "2026-11-30T18:00:00Z",
      "scheduled_post_date": "2026-12-05T18:00:00Z"
    }
  ]
}

Fields

FieldTypeRequiredNotes
titlestringyes
descriptionstringno
currencystringnoISO 4217, default USD
deadlinedatetimenoBrief expires at deadline + grace_hours
grace_hoursintnoGrace after the deadline before expiry (default 24, 0 = none)
required_nichestringnoMatching creators are surfaced first
selection_modestringnobrand_selects (default) or first_come
pricing_modelstringnofixed (default) or cpm
requires_brand_approvalboolnoDrafts need your review before posting
requires_shippingboolnoPhysical samples shipped to creators
post_onlyboolnoInfluencers post pre-made content (no creation)
quantityintnoAuto-generate this many deliverables (alternative to deliverables[])
per_item_amountnumbernoPer-deliverable amount when using quantity
brand_media_urlsstring[]post_onlyShared media copied to every quantity deliverable
brand_captionstringpost_onlyShared caption/text for post-only briefs
total_budgetnumberfor cpmExplicit budget pool (per-1k-views pricing)
deliverablesarrayyesAt least 1 for fixed (or use quantity)
deliverables[].titlestringyes
deliverables[].descriptionstringno
deliverables[].amountnumberyesMust be &gt; 0 for fixed
deliverables[].due_datedatetimeno
deliverables[].scheduled_post_datedatetimenoWhen the influencer posts; triggers reminders
deliverables[].brand_media_urlsstring[]post_onlyPre-made media for this deliverable
deliverables[].brand_captionstringpost_onlyCaption/text for this deliverable

Response 201 — the created Brief object.

Validation rules

  • fixed: every deliverable needs amount > 0; total_budget is derived.
  • cpm: total_budget > 0 is required; deliverable amounts are ignored.
  • post_only: each deliverable needs brand_media_urls or brand_caption.
GET/briefs· List my briefs

List your own briefs (newest first). Response is an array of Brief objects each with an added remaining_budget field.

GET/briefs/:id· Fetch one brief

Fetch one brief with its full deliverables array.

POST/briefs/:id/checkout· Fund from wallet

Fund the brief from your prepaid wallet. Debits the budget instantly and opens the brief for applications. No request body.

Response 200

json
{ "funded": true, "balance_after": 4900.0 }

Errors

  • 409 if the brief is not in draft status.
  • 409 if the wallet balance is insufficient (message includes the shortfall).

Deliverables

POST/briefs/:id/deliverables· Append deliverables

Append deliverables to a draft brief and recompute its budget.

Body

json
{
  "deliverables": [
    { "title": "Unboxing + first impressions", "amount": 100.00, "brand_media_urls": ["https://.../unbox.mp4"], "brand_caption": "Full unboxing" }
  ]
}

Response 200 — updated Brief object.

Errors

  • 409 if the brief is not in draft status.
POST/briefs/:id/deliverables/:did/content· Attach / replace brand content

Attach (or replace) brand-supplied content on a post-only deliverable. Upload files via the platform upload endpoint first, then pass the returned URLs here.

Body

json
{ "media_urls": ["https://cdn.example.com/launch.mp4"], "caption": "Spring is here!" }

Response 200 — the updated deliverable

json
{
  "id": "a671c830-...",
  "title": "Spring Launch",
  "amount": 10,
  "status": "unassigned",
  "brand_media_urls": ["https://cdn.example.com/launch.mp4"],
  "brand_caption": "Spring is here!"
}

Applicants

GET/briefs/:id/applicants· Pending applications

Pending creator applications for a brief.

Response 200

json
[
  {
    "id": "8f9c...",
    "brief_id": "e1b2...",
    "creator_id": "3f0f...",
    "pitch": "Love this brand — perfect niche fit!",
    "status": "pending",
    "creator": { "id": "3f0f...", "display_name": "Maya Wellness", "rate": 1500.0, "niches": ["health"], "types": ["creator"] }
  }
]

Invites

POST/briefs/:id/invite· Invite a creator

Privately invite a creator to specific deliverables.

Body

json
{
  "creator_id": "3f0f...",
  "deliverable_ids": ["d1a2...", "d2b3..."],
  "proposed_amount": 100.00,
  "message": "Hi Maya — we'd love you on this!"
}

Fields

FieldTypeRequiredNotes
creator_iduuidyesFrom GET /creators or applicants
deliverable_idsarrayyes≥ 1 unassigned deliverable of this brief
proposed_amountnumbernoDefaults to the deliverable amount
messagestringno

Response 201 — the invite object.

Errors

  • 409 if a deliverable is already assigned, or the brief is not open.

Select (propose terms)

POST/briefs/:id/select· Propose terms to an applicant

Propose terms to a pending applicant for one deliverable, opening a negotiation.

Body

json
{
  "creator_id": "3f0f...",
  "deliverable_id": "d1a2...",
  "agreed_amount": 100.00,
  "notes": "Any additional guidance"
}

Response 201 — an Agreement object in negotiating status. The creator must accept (in the app) before work starts and before budget is committed.

Errors

  • 404 if there is no pending application from that creator.

Submissions

GET/briefs/:id/submissions· Drafts + proofs for a brief

All submissions for a brief (drafts and proofs), newest first. Each entry preloads its assignment, assignment.creator, and assignment.deliverable.

Response 200

json
[
  {
    "id": "c4d5...",
    "assignment_id": "a1b2...",
    "kind": "draft",
    "content_links": ["https://..."],
    "screenshot_urls": [],
    "notes": "Ready for review",
    "reported_views": 0,
    "verified_views": null,
    "status": "pending_review",
    "assignment": {
      "id": "a1b2...",
      "agreed_amount": 100.0,
      "status": "awaiting_brand_review",
      "creator": { "id": "3f0f...", "display_name": "Maya Wellness" },
      "deliverable": { "id": "d1a2...", "title": "Gym lookbook video" }
    }
  }
]

Submission kinds & statuses

KindMeaning
draftPre-posting draft, awaiting your review (only when requires_brand_approval)
proofPosted content, verified by our team before payment

Submission statuses: pending_review, approved, rejected, changes_requested, revision_requested.

Brand review (drafts)

POST/submissions/:id/review· Approve or request changes

Approve or request changes on a draft submission.

Body

json
{ "status": "approved", "notes": "Looks great, post it!" }

status is one of: approved | changes_requested | rejected.

Response 200 — the BrandReview record.

Errors

  • 409 if the submission is not a draft or was already reviewed.
  • 403 if the submission belongs to another account.

Confirm & pay

POST/submissions/:id/confirm· Confirm & release payment

Final sign-off after our team approves the proof. Releases the held escrow payment to the creator.

No request body.

Response 200 — the released Payment object.

Errors

  • 409 if the submission is not approved or the assignment is already paid.
  • 403 if the submission belongs to another account.
Reference

Object reference

Brief object

json
{
  "id": "e1b2...",
  "title": "Summer Fitness Campaign",
  "description": "UGC videos for our activewear line",
  "total_budget": 200.0,
  "allocated_budget": 0.0,
  "remaining_budget": 200.0,
  "currency": "USD",
  "deadline": "2026-12-31T23:59:59Z",
  "required_niche": "health",
  "status": "draft",
  "selection_mode": "brand_selects",
  "pricing_model": "fixed",
  "requires_brand_approval": true,
  "requires_shipping": false,
  "deliverables": [
    {
      "id": "d1a2...",
      "title": "Gym lookbook video",
      "description": "60s vertical video",
      "amount": 100.0,
      "currency": "USD",
      "due_date": "2026-11-30T18:00:00Z",
      "scheduled_post_date": "2026-12-05T18:00:00Z",
      "sequence": 0,
      "status": "unassigned"
    }
  ]
}

Statuses

Brief statuses: draftopen in_progresscompleted | cancelled | expired (after deadline + grace_hours; new work blocked, in-flight finishes).

Deliverable statuses: unassignedassigned in_progresscompleted | cancelled.

Assignment statuses: assigned, proposed, awaiting_brand_review, changes_requested, awaiting_post, posted, revision_requested, approved, paid, cancelled.

Reference

Endpoint summary

MethodPathDescription
GET/creatorsCreator/clipper directory
POST/briefsCreate a brief (deliverables[] or quantity; post_only support)
GET/briefsList my briefs
GET/briefs/:idBrief + deliverables
POST/briefs/:id/checkoutFund from wallet (instant debit)
POST/briefs/:id/deliverablesAppend deliverables (draft only)
POST/briefs/:id/deliverables/:did/contentAttach brand-supplied content (post_only)
GET/briefs/:id/applicantsPending applicants
POST/briefs/:id/inviteInvite a creator
POST/briefs/:id/selectPropose terms to an applicant
GET/briefs/:id/submissionsDrafts + proofs for a brief
POST/submissions/:id/reviewReview a draft
POST/submissions/:id/confirmConfirm & release payment
GET/walletPrepaid balances (all currencies)
POST/wallet/top-upTop up wallet (hosted checkout)
GET/wallet/top-up/:id/statusPoll/verify a top-up
GET/wallet/transactionsWallet ledger
Operations

Usage & limits

  • Every API call is logged (license, endpoint, status) for auditing.
  • Keys are enforced for expiry on every request — an expired license immediately returns 401.
  • Rate limits may be applied per license. Plan for idempotent retries with backoff on 429 (when enabled) and 5xx.

Support

  • Contact support at onboarding with your license ID (visible in your dashboard).
  • Report bugs with the request/response payloads and timestamps; request logs help us investigate.