Your workspace to Scope, build, launch and grow.

Scope your ideas, build websites, apps and custom software, and manage your projects in one connected workspace. From integrations to security and launch, our team and Roddy help you move forward.

Free project scoping, no commitment

Scope

Your idea, scoped by Roddy and our team

Describe what you want to build. Roddy asks the right questions and records your requirements, then our team turns them into a proposal, a quote and a delivery plan.

Roddy scoping a website for Marina Crest Realty, a Dubai real estate company selling apartments and villas to international investors, and the scope it records as the chat goes.

  • Roddy asks, you answer. In plain language, any time. It records your requirements as you go, in your own discovery workspace.

    Ask Roddy
  • Our team shapes the plan. A person on the Roddy team reads what Roddy gathered and turns it into a proposal for you.

  • You approve, the project starts. Review the proposal and the quote in your dashboard. Approving the quote opens your project.

    Start a project

Build

Built by our team, around your goals

Roddy's developers build your website, app, custom software or automation from the plan you approved, and test the work as it goes.

The development team writing Marina Crest Realty's listing search, testing it and pushing it to preview.

Manage

Follow your project, every step

Progress, tasks and files, proposals and quotes, and meetings with the team, in your Roddy Labs dashboard during the build and after launch.

Marina Crest Realty following the project in their Roddy Labs dashboard: tasks and their status, activity, the team and the next meeting.

Integrate

Connected to what you already use

We connect your product to APIs, payment providers, tools and the systems you already run. For businesses, the Roddy Labs B2B API brings gift cards, eSIMs, credit and data, and bills into your own app.

Request API access
client.js · my-store · Roddy Labs gift-cards.js · my-store · Roddy Labs esims.js · my-store · Roddy Labs credit-data.js · my-store · Roddy Labs bills.js · my-store · Roddy Labs client.php · my-store · Roddy Labs gift-cards.php · my-store · Roddy Labs esims.php · my-store · Roddy Labs credit-data.php · my-store · Roddy Labs bills.php · my-store · Roddy Labs client.py · my-store · Roddy Labs gift_cards.py · my-store · Roddy Labs esims.py · my-store · Roddy Labs credit_data.py · my-store · Roddy Labs bills.py · my-store · Roddy Labs env.sh · my-store · Roddy Labs gift-cards.sh · my-store · Roddy Labs esims.sh · my-store · Roddy Labs credit-data.sh · my-store · Roddy Labs bills.sh · my-store · Roddy Labs
// One place for the base URL and your API key
const API = 'https://api.roddylabs.com/v1'
const KEY = process.env.RODDY_LABS_API_KEY
export async function api(method, path, body) {
const res = await fetch(API + path, {
method,
headers: {
Authorization: 'Bearer ' + KEY,
'Content-Type': 'application/json',
},
body: body && JSON.stringify(body),
})
return res.json()
}
import { api } from './client.js'
// Buy a gift card; the code is emailed once it is DONE
export async function sellGiftCard(email) {
const purchase = await api('POST', '/gift-cards/purchases', {
offerId: 'GC-GAMING-USD-25',
transactionId: crypto.randomUUID(),
fields: [{ key: 'email', value: email }],
})
return purchase.status // ACCEPTED, then DONE
}
import { api } from './client.js'
// Pick a travel offer for the country, then buy the eSIM
export async function sellEsim(country) {
const [offer] = await api('GET', '/esims/offers?country=' + country)
const esim = await api('POST', '/esims/purchases', {
offerId: offer.offerId,
transactionId: crypto.randomUUID(),
})
return esim.activationCode // for the QR
}
import { api } from './client.js'
// Send airtime or a data bundle to a phone number
export async function topUp(phone, offerId) {
const topup = await api('POST', '/topups/purchases', {
offerId,
recipientPhoneNumber: phone,
transactionId: crypto.randomUUID(),
})
return topup.status // ACCEPTED, then DONE
}
import { api } from './client.js'
// Pay a prepaid electricity bill; the token comes with DONE
export async function payBill(meter, offerId, amountCents) {
const bill = await api('POST', '/bills/purchases', {
offerId,
amount: amountCents,
transactionId: crypto.randomUUID(),
fields: [{ key: 'meterNumber', value: meter }],
})
return bill.status // ACCEPTED, then DONE
}
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
// One place for the base URL and your API key
function api(string $method, string $path, array $body = []): array
{
$key = getenv('RODDY_LABS_API_KEY');
$client = new Client([
'base_uri' => 'https://api.roddylabs.com/v1/',
'headers' => ['Authorization' => "Bearer $key"],
]);
$res = $client->request($method, $path, ['json' => $body ?: null]);
return json_decode($res->getBody(), true);
}
<?php
require 'client.php';
// Buy a gift card; the code is emailed once it is DONE
function sellGiftCard(string $email): string
{
$purchase = api('POST', 'gift-cards/purchases', [
'offerId' => 'GC-GAMING-USD-25',
'transactionId' => bin2hex(random_bytes(16)),
'fields' => [['key' => 'email', 'value' => $email]],
]);
return $purchase['status']; // ACCEPTED, then DONE
}
<?php
require 'client.php';
// Pick a travel offer for the country, then buy the eSIM
function sellEsim(string $country): string
{
$offer = api('GET', "esims/offers?country=$country")[0];
$esim = api('POST', 'esims/purchases', [
'offerId' => $offer['offerId'],
'transactionId' => bin2hex(random_bytes(16)),
]);
return $esim['activationCode']; // for the QR
}
<?php
require 'client.php';
// Send airtime or a data bundle to a phone number
function topUp(string $phone, string $offerId): string
{
$topup = api('POST', 'topups/purchases', [
'offerId' => $offerId,
'recipientPhoneNumber' => $phone,
'transactionId' => bin2hex(random_bytes(16)),
]);
return $topup['status']; // ACCEPTED, then DONE
}
<?php
require 'client.php';
// Pay a prepaid electricity bill; the token comes with DONE
function payBill(string $meter, string $offerId, int $amountCents): string
{
$bill = api('POST', 'bills/purchases', [
'offerId' => $offerId,
'amount' => $amountCents,
'transactionId' => bin2hex(random_bytes(16)),
'fields' => [['key' => 'meterNumber', 'value' => $meter]],
]);
return $bill['status']; // ACCEPTED, then DONE
}
import os
import requests
# One place for the base URL and your API key
API = 'https://api.roddylabs.com/v1'
KEY = os.environ['RODDY_LABS_API_KEY']
def api(method, path, body=None):
res = requests.request(method, API + path, json=body, headers={
'Authorization': 'Bearer ' + KEY,
})
res.raise_for_status()
return res.json()
import uuid
from client import api
# Buy a gift card; the code is emailed once it is DONE
def sell_gift_card(email):
purchase = api('POST', '/gift-cards/purchases', {
'offerId': 'GC-GAMING-USD-25',
'transactionId': str(uuid.uuid4()),
'fields': [{'key': 'email', 'value': email}],
})
return purchase['status'] # ACCEPTED, then DONE
import uuid
from client import api
# Pick a travel offer for the country, then buy the eSIM
def sell_esim(country):
offer = api('GET', '/esims/offers?country=' + country)[0]
esim = api('POST', '/esims/purchases', {
'offerId': offer['offerId'],
'transactionId': str(uuid.uuid4()),
})
return esim['activationCode'] # for the QR
import uuid
from client import api
# Send airtime or a data bundle to a phone number
def top_up(phone, offer_id):
topup = api('POST', '/topups/purchases', {
'offerId': offer_id,
'recipientPhoneNumber': phone,
'transactionId': str(uuid.uuid4()),
})
return topup['status'] # ACCEPTED, then DONE
import uuid
from client import api
# Pay a prepaid electricity bill; the token comes with DONE
def pay_bill(meter, offer_id, amount_cents):
bill = api('POST', '/bills/purchases', {
'offerId': offer_id,
'amount': amount_cents,
'transactionId': str(uuid.uuid4()),
'fields': [{'key': 'meterNumber', 'value': meter}],
})
return bill['status'] # ACCEPTED, then DONE
# One place for the base URL and your API key
export API="https://api.roddylabs.com/v1"
export RODDY_LABS_API_KEY="your_api_key"
# Check the key works
curl "$API/ping" -H "Authorization: Bearer $RODDY_LABS_API_KEY"
# Buy a gift card; the code is emailed once it is DONE
curl -X POST "$API/gift-cards/purchases" \
-H "Authorization: Bearer $RODDY_LABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"offerId": "GC-GAMING-USD-25",
"transactionId": "0b7c6f2e-5d1a-4c1e-9f3a-2e8b1c7d4a90",
"fields": [{ "key": "email", "value": "ada@example.com" }]
}'
# Pick a travel offer for the country, then buy the eSIM
curl "$API/esims/offers?country=FR" \
-H "Authorization: Bearer $RODDY_LABS_API_KEY"
curl -X POST "$API/esims/purchases" \
-H "Authorization: Bearer $RODDY_LABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"offerId": "ESIM-TRAVEL-5GB-30D",
"transactionId": "a83d1f60-2c4b-4e8a-9b57-6d0e3c1f9a24"
}'
# Send airtime or a data bundle to a phone number
curl -X POST "$API/topups/purchases" \
-H "Authorization: Bearer $RODDY_LABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"offerId": "TOPUP-AIRTIME-USD-10",
"recipientPhoneNumber": "+15555550100",
"transactionId": "5e2d9a14-8c3b-4f70-a1d6-7b9e0c2f4a18"
}'
# Pay a prepaid electricity bill; the token comes with DONE
curl -X POST "$API/bills/purchases" \
-H "Authorization: Bearer $RODDY_LABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"offerId": "BILL-ELECTRICITY",
"amount": 1840,
"transactionId": "c41f7b08-2a6e-4d93-b5c1-e8f04a7d6b32",
"fields": [{ "key": "meterNumber", "value": "04127781903" }]
}'

~/my-store $ npm run ping

→ GET api.roddylabs.com/v1/ping 200 OK

{ "ok": true, "mode": "test", "business": "my-store" }

✓ API key accepted test mode

~/my-store $ npm run gift-cards

→ POST api.roddylabs.com/v1/gift-cards/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "0b7c6f2e-5d1a-4c1e-9f3a-2e8b1c7d4a90" }

✓ status DONE webhook received

~/my-store $ npm run esims

→ GET api.roddylabs.com/v1/esims/offers 200 OK

→ POST api.roddylabs.com/v1/esims/purchases 200 OK

{ "status": "DONE", "iccid": "8910000000000009125", "activationCode": "LPA:1$smdp.example.com$K2-7Q4LMP" }

✓ status DONE QR code ready

~/my-store $ npm run credit-data

→ POST api.roddylabs.com/v1/topups/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "5e2d9a14-8c3b-4f70-a1d6-7b9e0c2f4a18" }

✓ status DONE webhook received

~/my-store $ npm run bills

→ POST api.roddylabs.com/v1/bills/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "c41f7b08-2a6e-4d93-b5c1-e8f04a7d6b32" }

✓ status DONE token issued

~/my-store $ php ping.php

→ GET api.roddylabs.com/v1/ping 200 OK

{ "ok": true, "mode": "test", "business": "my-store" }

✓ API key accepted test mode

~/my-store $ php gift-cards.php

→ POST api.roddylabs.com/v1/gift-cards/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "0b7c6f2e-5d1a-4c1e-9f3a-2e8b1c7d4a90" }

✓ status DONE webhook received

~/my-store $ php esims.php

→ GET api.roddylabs.com/v1/esims/offers 200 OK

→ POST api.roddylabs.com/v1/esims/purchases 200 OK

{ "status": "DONE", "iccid": "8910000000000009125", "activationCode": "LPA:1$smdp.example.com$K2-7Q4LMP" }

✓ status DONE QR code ready

~/my-store $ php credit-data.php

→ POST api.roddylabs.com/v1/topups/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "5e2d9a14-8c3b-4f70-a1d6-7b9e0c2f4a18" }

✓ status DONE webhook received

~/my-store $ php bills.php

→ POST api.roddylabs.com/v1/bills/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "c41f7b08-2a6e-4d93-b5c1-e8f04a7d6b32" }

✓ status DONE token issued

~/my-store $ python ping.py

→ GET api.roddylabs.com/v1/ping 200 OK

{ "ok": true, "mode": "test", "business": "my-store" }

✓ API key accepted test mode

~/my-store $ python gift_cards.py

→ POST api.roddylabs.com/v1/gift-cards/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "0b7c6f2e-5d1a-4c1e-9f3a-2e8b1c7d4a90" }

✓ status DONE webhook received

~/my-store $ python esims.py

→ GET api.roddylabs.com/v1/esims/offers 200 OK

→ POST api.roddylabs.com/v1/esims/purchases 200 OK

{ "status": "DONE", "iccid": "8910000000000009125", "activationCode": "LPA:1$smdp.example.com$K2-7Q4LMP" }

✓ status DONE QR code ready

~/my-store $ python credit_data.py

→ POST api.roddylabs.com/v1/topups/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "5e2d9a14-8c3b-4f70-a1d6-7b9e0c2f4a18" }

✓ status DONE webhook received

~/my-store $ python bills.py

→ POST api.roddylabs.com/v1/bills/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "c41f7b08-2a6e-4d93-b5c1-e8f04a7d6b32" }

✓ status DONE token issued

~/my-store $ sh env.sh

→ GET api.roddylabs.com/v1/ping 200 OK

{ "ok": true, "mode": "test", "business": "my-store" }

✓ API key accepted test mode

~/my-store $ sh gift-cards.sh

→ POST api.roddylabs.com/v1/gift-cards/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "0b7c6f2e-5d1a-4c1e-9f3a-2e8b1c7d4a90" }

✓ status DONE webhook received

~/my-store $ sh esims.sh

→ GET api.roddylabs.com/v1/esims/offers 200 OK

→ POST api.roddylabs.com/v1/esims/purchases 200 OK

{ "status": "DONE", "iccid": "8910000000000009125", "activationCode": "LPA:1$smdp.example.com$K2-7Q4LMP" }

✓ status DONE QR code ready

~/my-store $ sh credit-data.sh

→ POST api.roddylabs.com/v1/topups/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "5e2d9a14-8c3b-4f70-a1d6-7b9e0c2f4a18" }

✓ status DONE webhook received

~/my-store $ sh bills.sh

→ POST api.roddylabs.com/v1/bills/purchases 200 OK

{ "status": "ACCEPTED", "transactionId": "c41f7b08-2a6e-4d93-b5c1-e8f04a7d6b32" }

✓ status DONE token issued

Secure

Protected from the start

Security is planned in from the first scope. On our own platform, new devices sign in with a one-time code, passwords are stored only as one-way hashes and card details are never stored.

Visit the Trust Center

The security review for Marina Crest Realty's website passing eight checks before launch.

Launch

Live, and looked after

Before release the work is tested and prepared for production. Then it goes live, and our team stays on for support and improvements.

Marina Crest Realty's website deploying and going live: a villa under the headline and a property search.

FAQ

Questions about
Roddy Labs?

Straight answers on how projects run, who builds them and what is ready today.

What is Roddy Labs?

Roddy Labs is the workspace where ideas become digital products. You scope your idea with Roddy, our team sends you a proposal and a quote, and you follow your project in your Roddy Labs dashboard.

Who is Roddy Labs for?

Developers, students, startups, businesses and organizations: anyone who wants to plan, build and launch a website, an app, custom software or an automation.

How does a project start?

Tell Roddy what you want to build. It asks the right questions and records your requirements in your discovery workspace. A person on the Roddy team turns them into a proposal and a quote, and approving the quote opens your project.

Is Roddy building my project?

No. Roddy is Roddy Technologies' own assistant: it helps you scope your idea and answers your questions at any time. Your project is planned, built and tested by Roddy's development team.

What does a project cost?

It depends on what you need. Scoping with Roddy is free, and you see a quote for your project, and approve it, before any work starts.

Where do I follow my project?

In your Roddy Labs dashboard: progress, tasks and files, proposals and quotes, meetings with the team and notifications, in one place. It stays there after launch.

Can I use the Roddy Labs B2B API today?

Yes, by request. The API brings gift cards, eSIMs, credit and data, and bills into your own app: ask our team and we will set up your access.

How do you protect my account and data?

Signing in from a new device asks for a one-time code sent to your email, passwords are stored only as one-way hashes, and card details are never stored. The Trust Center sets out the rest.

What happens after launch?

Your project stays in your dashboard, and our team stays on for support and further improvements.

Bring your idea to Roddy Labs.

Scope it with Roddy today. Our team plans it, builds it and launches it with you, and you follow every step in your workspace.