DILSE · for developers

Build with DILSE

Organisations post opportunities, events, courses and more on DILSE once. With DILSE’s open API, your website or tool can show them too, kept up to date by itself, so their work reaches more people. It is free for everyone, and you can start without signing up. Back to DILSE

What you can use

Six collections, each filterable, each also a feed. Only real work that the DILSE team has reviewed and that is live comes back, and only when its owner shares it beyond DILSE (they can switch that off). Real work is only beginning to arrive, so each collection also has samples from DILSE’s demonstration to build against, always marked as samples and never mixed in.

Opportunities 0 live opportunities

DILSE Youth

Jobs, fellowships, internships and volunteering, posted by organisations in India’s development sector. Job boards, campus portals and NGO career pages show them; anyone can follow a feed of them.

Events 0 live events

The Collective

Upcoming workshops, webinars and gatherings, with their dates and where they happen. Event calendars and newsletters list them; anyone can subscribe to them in Google Calendar or Outlook.

Courses 0 live courses

DILSE Learn

Courses made for people working in the sector: the catalogue, with who made each one. Skilling portals, universities and learning platforms list them.

Projects 0 live projects

India Impact Map

Projects on the ground, where they are and who runs them. Dashboards, funders and researchers see who is working where.

Resources 0 live resources

Shared Library

Reports, toolkits and case studies the sector has shared. Knowledge portals and course platforms link to them.

Stories 0 live stories

Realising India

Moments from the field that their storytellers chose to make public. Media and donor reports carry them, always credited to the storyteller.

Also one at a time, by id: organisations, funding asks, digital tools.

Without writing any code

  • RSS feeds: paste a feed link into WordPress’s RSS block, a feed reader, a newsletter tool or Zapier. For example, every opening on DILSE: https://dilse.duckdns.org/api/v1/opportunities.rss, or only fellowships in Rajasthan: add ?state=Rajasthan&type=Fellowship.
  • A calendar of events: in Google Calendar choose Other calendars → From URL and paste https://dilse.duckdns.org/api/v1/events.ics. New events appear by themselves.
  • Embeds and lists: a live card or a self-updating list on your website, and the WordPress plugin, are on Put DILSE on your website.

Quick start

  1. Look around without a key. Open https://dilse.duckdns.org/api/v1 in your browser: it lists every collection and its links. Without a key you have 200 calls a day, enough to try things and to run a feed.
  2. Make a free key below for 10,000 calls a day, and send it with each call:
    curl "https://dilse.duckdns.org/api/v1/opportunities?state=Rajasthan&type=Fellowship" \
      -H "Authorization: Bearer YOUR_KEY"
  3. Show it, with credit. Every entry has url, its page on DILSE: link to it. The whole thing (details) carries an attribution line to show beside it.
    const res = await fetch('https://dilse.duckdns.org/api/v1/events?limit=5')
    const { data } = await res.json()
    for (const event of data) {
      // Show the title, and always link back to DILSE.
      console.log(event.title, event.organisation, event.url)
    }

What comes back, in short:

{
  "data": [
    {
      "id": "yl-…",
      "type": "opportunity",
      "title": "Field fellowship, water security",
      "organisation": "An organisation on DILSE",
      "state": "Rajasthan",
      "category": "Fellowship",
      "themes": [],
      "starts_at": null,
      "url": "https://dilse.duckdns.org/share/opening/yl-…",
      "details": "https://dilse.duckdns.org/api/v1/opportunities/yl-…",
      "sample": false
    }
  ],
  "total": 1,
  "next": null,
  "licence": {
    "name": "CC BY 4.0",
    "url": "https://creativecommons.org/licenses/by/4.0/"
  }
}

Pages hold 20 entries (up to 100 with limit). When there are more, next_url is the next page.

Try it now

This asks the real API from your browser, exactly as a website would.

GET /api/v1/opportunities?limit=3&sample=true

Get a free key

Keys are free, for non-profits and companies alike. A key lets you make more calls, and lets us tell you if something changes.

Looking for your keys…

Be told the moment something changes

Instead of asking DILSE every hour, give it an address on your server. Within a minute of a new fellowship in Bihar, say, going live, DILSE sends it there; when something is closed, withdrawn, taken down or kept inside by its owner, DILSE sends that too, so you can take it down.

  • What comes: opportunity.published, opportunity.removed, and the same for events, courses, projects, resources and stories. A test sends ping.
  • How: an HTTPS POST of JSON, signed the Standard Webhooks way, so the free libraries for it check the signature for you.
  • If your server does not answer 2xx, DILSE tries again after 1 minute, 5, 30, 2 hours, 6 and 12, then gives up on that message. After 20 failures in a row the webhook is paused, and you can resume it here.
  • Only to public addresses: DILSE never sends to a private network or to the server’s own machine.
{
  "type": "opportunity.published",
  "timestamp": "2026-10-10T09:30:00.000Z",
  "data": {
    "id": "yl-…",
    "type": "opportunity",
    "title": "Field fellowship, water security",
    "organisation": "An organisation on DILSE",
    "state": "Bihar",
    "category": "Fellowship",
    "themes": [],
    "starts_at": null,
    "url": "https://dilse.duckdns.org/share/opening/yl-…",
    "details": "https://dilse.duckdns.org/api/v1/opportunities/yl-…",
    "sample": false
  }
}

Checking that a message came from DILSE, in Node.js (the same in any language: an HMAC-SHA256):

import { createHmac, timingSafeEqual } from 'node:crypto'

// headers: webhook-id, webhook-timestamp, webhook-signature; body: the raw text
function fromDilse(headers, body, secret /* whsec_… */) {
  const key = Buffer.from(secret.replace('whsec_', ''), 'base64')
  const signed = `${headers['webhook-id']}.${headers['webhook-timestamp']}.${body}`
  const expected = createHmac('sha256', key).update(signed).digest('base64')
  const old = Math.abs(Date.now() / 1000 - Number(headers['webhook-timestamp'])) > 300
  return !old && headers['webhook-signature'].split(' ').some((s) => {
    const sig = s.replace(/^v1,/, '')
    return sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
  })
}

Looking for your webhooks…

Post into DILSE for organisations

If you run a jobs board, a volunteering platform or a network’s own system, you can send opportunities and events into DILSE for the organisations that ask you to, so they write them once. Three yeses come first, and one after:

  1. The DILSE team approves you. Beside your key above, say what you will send in, for which organisations, and how often.
  2. Each organisation says yes. Once approved, your key shows a connect link. Send it to the organisation’s person in charge on DILSE; they open it and allow you. They can take it back at any time.
  3. You send things in, with your key, for an organisation that allowed you.
  4. The DILSE team reads every one before it goes live, even for organisations whose own listings would not wait. What a machine sends in never goes live by itself.
curl -X POST https://dilse.duckdns.org/api/v1/opportunities \
  -H "Authorization: Bearer $DILSE_KEY" -H "content-type: application/json" \
  -d '{ "organisation": "<id from /connected>", "external_id": "job-4417",
        "title": "Field fellow, water and sanitation", "type": "Fellowship", "mode": "Onsite",
        "state": "Bihar", "city": "Gaya", "duration": "12 months", "hours_per_week": 40,
        "description": "A year with village water committees…",
        "support": "₹15,000 a month and travel", "closes_at": "2026-12-31" }'
SendWhat it does
GET /api/v1/connectedThe organisations that allowed you, with the id to send as organisation.
POST /api/v1/opportunitiestitle, type (Volunteering, Internship, Fellowship), mode (Onsite, Remote, Hybrid), state, city, duration, hours_per_week, skills, experience_level (Beginner-friendly, Some experience, Experienced), description, expectations, support (what it pays or covers: always needed), sdgs (1–17), closes_at. DILSE Youth’s own checks apply, and the answer says what is missing.
POST /api/v1/eventsname, format (INPERSON, ONLINE, HYBRID), starts_at, ends_at, venue, platform, description, tags, registration_url, contact_email.
Both also needorganisation, and external_id: your own id for it. Sending the same external_id again changes it (and it is read again) instead of adding another.
GET /api/v1/submissionsEverything you sent in, where each stands (review, live, changes, declined…) and what the team said.
DELETE /api/v1/opportunities/{id}Takes one back, by DILSE’s id or your external_id. The same for events.

Errors add not_partner (not approved yet) and not_allowed (that organisation has not allowed you, or the person who did is no longer in charge of it). Posting is only from servers, never from a browser.

Shared codes, so tools can match each other

Two tools that never met can match each other’s data if they use the same codes. DILSE publishes one set, free to use, and every entry from the API carries them in codes beside the words.

VocabularyWhat it holds
GET /api/v1/vocabularies/statesLGD state codes, as India’s own systems use them. 36 in all.
GET /api/v1/vocabularies/districtsLGD district codes, each with its state’s code, and its Census 2011 code where there is one. 765 in all.
GET /api/v1/vocabularies/themesThe causes work is about. Each has the words DILSE’s apps use for it, and the SDGs it serves. 18 in all.
GET /api/v1/vocabularies/sdgsThe UN’s seventeen goals, by number. 17 in all.
GET /api/v1/vocabularies/languagesBCP 47 tags: India’s scheduled languages, English, and the others DILSE holds. 25 in all.
GET /api/v1/vocabularies/skillsWhat people in the sector learn: DILSE Learn’s areas. 14 in all.

Add .csv for a spreadsheet, q= to find one in any spelling DILSE knows (“Orissa” finds Odisha), and state= for one state’s districts. States and districts are India’s own Local Government Directory codes, as of 2023-10-20; goals are the UN’s numbers; languages are the tags every phone already uses.

Certificates anyone can check

A record on someone’s My Records, or a DILSE Learn certificate, can leave DILSE as a signed file its holder keeps, in the open formats made for it: W3C Verifiable Credentials 2.0, as an Open Badges 3.0 credential, sealed with Ed25519. Only the person it names can make one, from their own record. Your tool can accept them without calling anyone.

  • Check the seal yourself with DILSE’s public key from GET /api/v1/credentials/issuer (a did:key, and the same key as a JWKS).
  • Or ask DILSE: POST /api/v1/credentials/verify with { "credential": "…" } says whether DILSE signed it, whether it was changed, and whether it still stands today.
  • People can check one too, with no account, on /verify.
  • It carries only what /verify shows: the name on the record, what they did, who said so, when. Never an email address or an account.

Which tools can talk to each other

Builders listing a tool in the Digital Tools Registry can say how it connects: what it shares, what it takes in, the open standards it uses, and where its API is. DILSE then shows which tools can pass what to which, itself among them.

GET /api/v1/connections lists them, with the pairs. It is what each builder says of their own tool, read by the DILSE team when it was listed; DILSE has not tested the connections.

Reference

The full reference is in the OpenAPI format, which Postman, Swagger and code generators read: https://dilse.duckdns.org/api/v1/openapi.json.

Ask forWhat comes back
GET /api/v1Every collection, its live count and its links.
GET /api/v1/opportunitiesA page of opportunities. Filters: state, type, org, and q for words.
GET /api/v1/eventsA page of events. Filters: org, type, and q for words.
GET /api/v1/coursesA page of courses. Filters: org, theme, and q for words.
GET /api/v1/projectsA page of projects. Filters: state, org, theme, and q for words.
GET /api/v1/resourcesA page of resources. Filters: org, theme, type, and q for words.
GET /api/v1/storiesA page of stories. Filters: state, theme, org, and q for words.
GET /api/v1/opportunities/{id}One opportunity, whole: summary, facts, dates, where to apply, its embed and its attribution.
GET /api/v1/events/{id}One event, whole: summary, facts, dates, where to apply, its embed and its attribution.
GET /api/v1/courses/{id}One course, whole: summary, facts, dates, where to apply, its embed and its attribution.
GET /api/v1/projects/{id}One project, whole: summary, facts, dates, where to apply, its embed and its attribution.
GET /api/v1/resources/{id}One resource, whole: summary, facts, dates, where to apply, its embed and its attribution.
GET /api/v1/stories/{id}One story, whole: summary, facts, dates, where to apply, its embed and its attribution.
GET /api/v1/organisations/{id}An organisation’s public profile, and whether DILSE has verified it.
GET /api/v1/funding-asks/{id}A project or organisation seeking funds on DILSE Capital.
GET /api/v1/tools/{id}A tool in the Digital Tools Registry.
….rss · ….icsThe same collection as an RSS feed, or events as a calendar.

Add sample=true to anything for the samples instead. Errors come back as { "error": { "code", "message" } }: not_found, sample_only, bad_key (an unknown or revoked key: make a new one), rate_limited (see x-ratelimit-remaining and x-ratelimit-reset on every answer).

Rules

  • Free, under CC BY 4.0. Use it on any website or in any tool, commercial or not, under the Creative Commons Attribution licence.
  • Credit and link back. Show whose work it is, and link to its url on DILSE. Each thing’s attribution line does both.
  • Keep it current. Refresh at least once a day, and take down what DILSE no longer returns: it was closed, withdrawn or taken down.
  • Only what is public. Nothing personal is ever in the API: no accounts, no messages, no one under 18, nothing a person has not made public. Do not try to piece people together from it.
  • Samples are samples. Never show sample entries as real ones: they are invented, to build against.
  • Owners decide. An organisation can keep any of its listings inside DILSE; the API then stops returning it, and so must you.
  • Fair use. Stay within your allowance. A key used to harm the people or organisations on DILSE is revoked.

Coming next

  • Sign in with DILSE: people sign in to your tool with their DILSE account.

Building something for the sector and want it early? Tell the DILSE team what you are making.